editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//! * [`inlay_hint_cache`] - is a storage of inlay hints out of LSP requests, responsible for querying LSP and updating `display_map`'s state accordingly.
   11//!
   12//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   13//!
   14//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   15pub mod actions;
   16mod blink_manager;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod editor_settings_controls;
   22mod element;
   23mod git;
   24mod highlight_matching_bracket;
   25mod hover_links;
   26pub mod hover_popover;
   27mod indent_guides;
   28mod inlay_hint_cache;
   29pub mod items;
   30mod jsx_tag_auto_close;
   31mod linked_editing_ranges;
   32mod lsp_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  168use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  169use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  170use selections_collection::{
  171    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  172};
  173use serde::{Deserialize, Serialize};
  174use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  175use smallvec::{SmallVec, smallvec};
  176use snippet::Snippet;
  177use std::{
  178    any::{Any, TypeId},
  179    borrow::Cow,
  180    cell::{OnceCell, RefCell},
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  186    path::{Path, PathBuf},
  187    rc::Rc,
  188    sync::Arc,
  189    time::{Duration, Instant},
  190};
  191use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  192use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  193use theme::{
  194    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  195    observe_buffer_font_size_adjustment,
  196};
  197use ui::{
  198    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  199    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  200};
  201use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  202use workspace::{
  203    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  204    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  205    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  206    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  207    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  208    searchable::SearchEvent,
  209};
  210
  211use crate::{
  212    code_context_menus::CompletionsMenuSource,
  213    editor_settings::MultiCursorModifier,
  214    hover_links::{find_url, find_url_from_range},
  215    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  216};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  236
  237pub type RenderDiffHunkControlsFn = Arc<
  238    dyn Fn(
  239        u32,
  240        &DiffHunkStatus,
  241        Range<Anchor>,
  242        bool,
  243        Pixels,
  244        &Entity<Editor>,
  245        &mut Window,
  246        &mut App,
  247    ) -> AnyElement,
  248>;
  249
  250enum ReportEditorEvent {
  251    Saved { auto_saved: bool },
  252    EditorOpened,
  253    Closed,
  254}
  255
  256impl ReportEditorEvent {
  257    pub fn event_type(&self) -> &'static str {
  258        match self {
  259            Self::Saved { .. } => "Editor Saved",
  260            Self::EditorOpened => "Editor Opened",
  261            Self::Closed => "Editor Closed",
  262        }
  263    }
  264}
  265
  266struct InlineValueCache {
  267    enabled: bool,
  268    inlays: Vec<InlayId>,
  269    refresh_task: Task<Option<()>>,
  270}
  271
  272impl InlineValueCache {
  273    fn new(enabled: bool) -> Self {
  274        Self {
  275            enabled,
  276            inlays: Vec::new(),
  277            refresh_task: Task::ready(None),
  278        }
  279    }
  280}
  281
  282#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  283pub enum InlayId {
  284    EditPrediction(usize),
  285    DebuggerValue(usize),
  286    // LSP
  287    Hint(usize),
  288    Color(usize),
  289}
  290
  291impl InlayId {
  292    fn id(&self) -> usize {
  293        match self {
  294            Self::EditPrediction(id) => *id,
  295            Self::DebuggerValue(id) => *id,
  296            Self::Hint(id) => *id,
  297            Self::Color(id) => *id,
  298        }
  299    }
  300}
  301
  302pub enum ActiveDebugLine {}
  303pub enum DebugStackFrameLine {}
  304enum DocumentHighlightRead {}
  305enum DocumentHighlightWrite {}
  306enum InputComposition {}
  307pub enum PendingInput {}
  308enum SelectedTextHighlight {}
  309
  310pub enum ConflictsOuter {}
  311pub enum ConflictsOurs {}
  312pub enum ConflictsTheirs {}
  313pub enum ConflictsOursMarker {}
  314pub enum ConflictsTheirsMarker {}
  315
  316#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  317pub enum Navigated {
  318    Yes,
  319    No,
  320}
  321
  322impl Navigated {
  323    pub fn from_bool(yes: bool) -> Navigated {
  324        if yes { Navigated::Yes } else { Navigated::No }
  325    }
  326}
  327
  328#[derive(Debug, Clone, PartialEq, Eq)]
  329enum DisplayDiffHunk {
  330    Folded {
  331        display_row: DisplayRow,
  332    },
  333    Unfolded {
  334        is_created_file: bool,
  335        diff_base_byte_range: Range<usize>,
  336        display_row_range: Range<DisplayRow>,
  337        multi_buffer_range: Range<Anchor>,
  338        status: DiffHunkStatus,
  339    },
  340}
  341
  342pub enum HideMouseCursorOrigin {
  343    TypingAction,
  344    MovementAction,
  345}
  346
  347pub fn init_settings(cx: &mut App) {
  348    EditorSettings::register(cx);
  349}
  350
  351pub fn init(cx: &mut App) {
  352    init_settings(cx);
  353
  354    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  355
  356    workspace::register_project_item::<Editor>(cx);
  357    workspace::FollowableViewRegistry::register::<Editor>(cx);
  358    workspace::register_serializable_item::<Editor>(cx);
  359
  360    cx.observe_new(
  361        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  362            workspace.register_action(Editor::new_file);
  363            workspace.register_action(Editor::new_file_vertical);
  364            workspace.register_action(Editor::new_file_horizontal);
  365            workspace.register_action(Editor::cancel_language_server_work);
  366            workspace.register_action(Editor::toggle_focus);
  367        },
  368    )
  369    .detach();
  370
  371    cx.on_action(move |_: &workspace::NewFile, cx| {
  372        let app_state = workspace::AppState::global(cx);
  373        if let Some(app_state) = app_state.upgrade() {
  374            workspace::open_new(
  375                Default::default(),
  376                app_state,
  377                cx,
  378                |workspace, window, cx| {
  379                    Editor::new_file(workspace, &Default::default(), window, cx)
  380                },
  381            )
  382            .detach();
  383        }
  384    });
  385    cx.on_action(move |_: &workspace::NewWindow, cx| {
  386        let app_state = workspace::AppState::global(cx);
  387        if let Some(app_state) = app_state.upgrade() {
  388            workspace::open_new(
  389                Default::default(),
  390                app_state,
  391                cx,
  392                |workspace, window, cx| {
  393                    cx.activate(true);
  394                    Editor::new_file(workspace, &Default::default(), window, cx)
  395                },
  396            )
  397            .detach();
  398        }
  399    });
  400}
  401
  402pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  403    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  404}
  405
  406pub trait DiagnosticRenderer {
  407    fn render_group(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  410        buffer_id: BufferId,
  411        snapshot: EditorSnapshot,
  412        editor: WeakEntity<Editor>,
  413        cx: &mut App,
  414    ) -> Vec<BlockProperties<Anchor>>;
  415
  416    fn render_hover(
  417        &self,
  418        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  419        range: Range<Point>,
  420        buffer_id: BufferId,
  421        cx: &mut App,
  422    ) -> Option<Entity<markdown::Markdown>>;
  423
  424    fn open_link(
  425        &self,
  426        editor: &mut Editor,
  427        link: SharedString,
  428        window: &mut Window,
  429        cx: &mut Context<Editor>,
  430    );
  431}
  432
  433pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  434
  435impl GlobalDiagnosticRenderer {
  436    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  437        cx.try_global::<Self>().map(|g| g.0.clone())
  438    }
  439}
  440
  441impl gpui::Global for GlobalDiagnosticRenderer {}
  442pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  443    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  444}
  445
  446pub struct SearchWithinRange;
  447
  448trait InvalidationRegion {
  449    fn ranges(&self) -> &[Range<Anchor>];
  450}
  451
  452#[derive(Clone, Debug, PartialEq)]
  453pub enum SelectPhase {
  454    Begin {
  455        position: DisplayPoint,
  456        add: bool,
  457        click_count: usize,
  458    },
  459    BeginColumnar {
  460        position: DisplayPoint,
  461        reset: bool,
  462        mode: ColumnarMode,
  463        goal_column: u32,
  464    },
  465    Extend {
  466        position: DisplayPoint,
  467        click_count: usize,
  468    },
  469    Update {
  470        position: DisplayPoint,
  471        goal_column: u32,
  472        scroll_delta: gpui::Point<f32>,
  473    },
  474    End,
  475}
  476
  477#[derive(Clone, Debug, PartialEq)]
  478pub enum ColumnarMode {
  479    FromMouse,
  480    FromSelection,
  481}
  482
  483#[derive(Clone, Debug)]
  484pub enum SelectMode {
  485    Character,
  486    Word(Range<Anchor>),
  487    Line(Range<Anchor>),
  488    All,
  489}
  490
  491#[derive(Clone, PartialEq, Eq, Debug)]
  492pub enum EditorMode {
  493    SingleLine,
  494    AutoHeight {
  495        min_lines: usize,
  496        max_lines: Option<usize>,
  497    },
  498    Full {
  499        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  500        scale_ui_elements_with_buffer_font_size: bool,
  501        /// When set to `true`, the editor will render a background for the active line.
  502        show_active_line_background: bool,
  503        /// When set to `true`, the editor's height will be determined by its content.
  504        sized_by_content: bool,
  505    },
  506    Minimap {
  507        parent: WeakEntity<Editor>,
  508    },
  509}
  510
  511impl EditorMode {
  512    pub fn full() -> Self {
  513        Self::Full {
  514            scale_ui_elements_with_buffer_font_size: true,
  515            show_active_line_background: true,
  516            sized_by_content: false,
  517        }
  518    }
  519
  520    #[inline]
  521    pub fn is_full(&self) -> bool {
  522        matches!(self, Self::Full { .. })
  523    }
  524
  525    #[inline]
  526    pub fn is_single_line(&self) -> bool {
  527        matches!(self, Self::SingleLine { .. })
  528    }
  529
  530    #[inline]
  531    fn is_minimap(&self) -> bool {
  532        matches!(self, Self::Minimap { .. })
  533    }
  534}
  535
  536#[derive(Copy, Clone, Debug)]
  537pub enum SoftWrap {
  538    /// Prefer not to wrap at all.
  539    ///
  540    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  541    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  542    GitDiff,
  543    /// Prefer a single line generally, unless an overly long line is encountered.
  544    None,
  545    /// Soft wrap lines that exceed the editor width.
  546    EditorWidth,
  547    /// Soft wrap lines at the preferred line length.
  548    Column(u32),
  549    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  550    Bounded(u32),
  551}
  552
  553#[derive(Clone)]
  554pub struct EditorStyle {
  555    pub background: Hsla,
  556    pub border: Hsla,
  557    pub local_player: PlayerColor,
  558    pub text: TextStyle,
  559    pub scrollbar_width: Pixels,
  560    pub syntax: Arc<SyntaxTheme>,
  561    pub status: StatusColors,
  562    pub inlay_hints_style: HighlightStyle,
  563    pub edit_prediction_styles: EditPredictionStyles,
  564    pub unnecessary_code_fade: f32,
  565    pub show_underlines: bool,
  566}
  567
  568impl Default for EditorStyle {
  569    fn default() -> Self {
  570        Self {
  571            background: Hsla::default(),
  572            border: Hsla::default(),
  573            local_player: PlayerColor::default(),
  574            text: TextStyle::default(),
  575            scrollbar_width: Pixels::default(),
  576            syntax: Default::default(),
  577            // HACK: Status colors don't have a real default.
  578            // We should look into removing the status colors from the editor
  579            // style and retrieve them directly from the theme.
  580            status: StatusColors::dark(),
  581            inlay_hints_style: HighlightStyle::default(),
  582            edit_prediction_styles: EditPredictionStyles {
  583                insertion: HighlightStyle::default(),
  584                whitespace: HighlightStyle::default(),
  585            },
  586            unnecessary_code_fade: Default::default(),
  587            show_underlines: true,
  588        }
  589    }
  590}
  591
  592pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  593    let show_background = language_settings::language_settings(None, None, cx)
  594        .inlay_hints
  595        .show_background;
  596
  597    HighlightStyle {
  598        color: Some(cx.theme().status().hint),
  599        background_color: show_background.then(|| cx.theme().status().hint_background),
  600        ..HighlightStyle::default()
  601    }
  602}
  603
  604pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  605    EditPredictionStyles {
  606        insertion: HighlightStyle {
  607            color: Some(cx.theme().status().predictive),
  608            ..HighlightStyle::default()
  609        },
  610        whitespace: HighlightStyle {
  611            background_color: Some(cx.theme().status().created_background),
  612            ..HighlightStyle::default()
  613        },
  614    }
  615}
  616
  617type CompletionId = usize;
  618
  619pub(crate) enum EditDisplayMode {
  620    TabAccept,
  621    DiffPopover,
  622    Inline,
  623}
  624
  625enum EditPrediction {
  626    Edit {
  627        edits: Vec<(Range<Anchor>, String)>,
  628        edit_preview: Option<EditPreview>,
  629        display_mode: EditDisplayMode,
  630        snapshot: BufferSnapshot,
  631    },
  632    Move {
  633        target: Anchor,
  634        snapshot: BufferSnapshot,
  635    },
  636}
  637
  638struct EditPredictionState {
  639    inlay_ids: Vec<InlayId>,
  640    completion: EditPrediction,
  641    completion_id: Option<SharedString>,
  642    invalidation_range: Range<Anchor>,
  643}
  644
  645enum EditPredictionSettings {
  646    Disabled,
  647    Enabled {
  648        show_in_menu: bool,
  649        preview_requires_modifier: bool,
  650    },
  651}
  652
  653enum EditPredictionHighlight {}
  654
  655#[derive(Debug, Clone)]
  656struct InlineDiagnostic {
  657    message: SharedString,
  658    group_id: usize,
  659    is_primary: bool,
  660    start: Point,
  661    severity: lsp::DiagnosticSeverity,
  662}
  663
  664pub enum MenuEditPredictionsPolicy {
  665    Never,
  666    ByProvider,
  667}
  668
  669pub enum EditPredictionPreview {
  670    /// Modifier is not pressed
  671    Inactive { released_too_fast: bool },
  672    /// Modifier pressed
  673    Active {
  674        since: Instant,
  675        previous_scroll_position: Option<ScrollAnchor>,
  676    },
  677}
  678
  679impl EditPredictionPreview {
  680    pub fn released_too_fast(&self) -> bool {
  681        match self {
  682            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  683            EditPredictionPreview::Active { .. } => false,
  684        }
  685    }
  686
  687    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  688        if let EditPredictionPreview::Active {
  689            previous_scroll_position,
  690            ..
  691        } = self
  692        {
  693            *previous_scroll_position = scroll_position;
  694        }
  695    }
  696}
  697
  698pub struct ContextMenuOptions {
  699    pub min_entries_visible: usize,
  700    pub max_entries_visible: usize,
  701    pub placement: Option<ContextMenuPlacement>,
  702}
  703
  704#[derive(Debug, Clone, PartialEq, Eq)]
  705pub enum ContextMenuPlacement {
  706    Above,
  707    Below,
  708}
  709
  710#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  711struct EditorActionId(usize);
  712
  713impl EditorActionId {
  714    pub fn post_inc(&mut self) -> Self {
  715        let answer = self.0;
  716
  717        *self = Self(answer + 1);
  718
  719        Self(answer)
  720    }
  721}
  722
  723// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  724// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  725
  726type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  727type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  728
  729#[derive(Default)]
  730struct ScrollbarMarkerState {
  731    scrollbar_size: Size<Pixels>,
  732    dirty: bool,
  733    markers: Arc<[PaintQuad]>,
  734    pending_refresh: Option<Task<Result<()>>>,
  735}
  736
  737impl ScrollbarMarkerState {
  738    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  739        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  740    }
  741}
  742
  743#[derive(Clone, Copy, PartialEq, Eq)]
  744pub enum MinimapVisibility {
  745    Disabled,
  746    Enabled {
  747        /// The configuration currently present in the users settings.
  748        setting_configuration: bool,
  749        /// Whether to override the currently set visibility from the users setting.
  750        toggle_override: bool,
  751    },
  752}
  753
  754impl MinimapVisibility {
  755    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  756        if mode.is_full() {
  757            Self::Enabled {
  758                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  759                toggle_override: false,
  760            }
  761        } else {
  762            Self::Disabled
  763        }
  764    }
  765
  766    fn hidden(&self) -> Self {
  767        match *self {
  768            Self::Enabled {
  769                setting_configuration,
  770                ..
  771            } => Self::Enabled {
  772                setting_configuration,
  773                toggle_override: setting_configuration,
  774            },
  775            Self::Disabled => Self::Disabled,
  776        }
  777    }
  778
  779    fn disabled(&self) -> bool {
  780        matches!(*self, Self::Disabled)
  781    }
  782
  783    fn settings_visibility(&self) -> bool {
  784        match *self {
  785            Self::Enabled {
  786                setting_configuration,
  787                ..
  788            } => setting_configuration,
  789            _ => false,
  790        }
  791    }
  792
  793    fn visible(&self) -> bool {
  794        match *self {
  795            Self::Enabled {
  796                setting_configuration,
  797                toggle_override,
  798            } => setting_configuration ^ toggle_override,
  799            _ => false,
  800        }
  801    }
  802
  803    fn toggle_visibility(&self) -> Self {
  804        match *self {
  805            Self::Enabled {
  806                toggle_override,
  807                setting_configuration,
  808            } => Self::Enabled {
  809                setting_configuration,
  810                toggle_override: !toggle_override,
  811            },
  812            Self::Disabled => Self::Disabled,
  813        }
  814    }
  815}
  816
  817#[derive(Clone, Debug)]
  818struct RunnableTasks {
  819    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  820    offset: multi_buffer::Anchor,
  821    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  822    column: u32,
  823    // Values of all named captures, including those starting with '_'
  824    extra_variables: HashMap<String, String>,
  825    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  826    context_range: Range<BufferOffset>,
  827}
  828
  829impl RunnableTasks {
  830    fn resolve<'a>(
  831        &'a self,
  832        cx: &'a task::TaskContext,
  833    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  834        self.templates.iter().filter_map(|(kind, template)| {
  835            template
  836                .resolve_task(&kind.to_id_base(), cx)
  837                .map(|task| (kind.clone(), task))
  838        })
  839    }
  840}
  841
  842#[derive(Clone)]
  843pub struct ResolvedTasks {
  844    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  845    position: Anchor,
  846}
  847
  848#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  849struct BufferOffset(usize);
  850
  851/// Addons allow storing per-editor state in other crates (e.g. Vim)
  852pub trait Addon: 'static {
  853    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  854
  855    fn render_buffer_header_controls(
  856        &self,
  857        _: &ExcerptInfo,
  858        _: &Window,
  859        _: &App,
  860    ) -> Option<AnyElement> {
  861        None
  862    }
  863
  864    fn to_any(&self) -> &dyn std::any::Any;
  865
  866    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  867        None
  868    }
  869}
  870
  871struct ChangeLocation {
  872    current: Option<Vec<Anchor>>,
  873    original: Vec<Anchor>,
  874}
  875impl ChangeLocation {
  876    fn locations(&self) -> &[Anchor] {
  877        self.current.as_ref().unwrap_or(&self.original)
  878    }
  879}
  880
  881/// A set of caret positions, registered when the editor was edited.
  882pub struct ChangeList {
  883    changes: Vec<ChangeLocation>,
  884    /// Currently "selected" change.
  885    position: Option<usize>,
  886}
  887
  888impl ChangeList {
  889    pub fn new() -> Self {
  890        Self {
  891            changes: Vec::new(),
  892            position: None,
  893        }
  894    }
  895
  896    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  897    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  898    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  899        if self.changes.is_empty() {
  900            return None;
  901        }
  902
  903        let prev = self.position.unwrap_or(self.changes.len());
  904        let next = if direction == Direction::Prev {
  905            prev.saturating_sub(count)
  906        } else {
  907            (prev + count).min(self.changes.len() - 1)
  908        };
  909        self.position = Some(next);
  910        self.changes.get(next).map(|change| change.locations())
  911    }
  912
  913    /// Adds a new change to the list, resetting the change list position.
  914    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  915        self.position.take();
  916        if let Some(last) = self.changes.last_mut()
  917            && group
  918        {
  919            last.current = Some(new_positions)
  920        } else {
  921            self.changes.push(ChangeLocation {
  922                original: new_positions,
  923                current: None,
  924            });
  925        }
  926    }
  927
  928    pub fn last(&self) -> Option<&[Anchor]> {
  929        self.changes.last().map(|change| change.locations())
  930    }
  931
  932    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  933        self.changes.last().map(|change| change.original.as_slice())
  934    }
  935
  936    pub fn invert_last_group(&mut self) {
  937        if let Some(last) = self.changes.last_mut()
  938            && let Some(current) = last.current.as_mut()
  939        {
  940            mem::swap(&mut last.original, current);
  941        }
  942    }
  943}
  944
  945#[derive(Clone)]
  946struct InlineBlamePopoverState {
  947    scroll_handle: ScrollHandle,
  948    commit_message: Option<ParsedCommitMessage>,
  949    markdown: Entity<Markdown>,
  950}
  951
  952struct InlineBlamePopover {
  953    position: gpui::Point<Pixels>,
  954    hide_task: Option<Task<()>>,
  955    popover_bounds: Option<Bounds<Pixels>>,
  956    popover_state: InlineBlamePopoverState,
  957    keyboard_grace: bool,
  958}
  959
  960enum SelectionDragState {
  961    /// State when no drag related activity is detected.
  962    None,
  963    /// State when the mouse is down on a selection that is about to be dragged.
  964    ReadyToDrag {
  965        selection: Selection<Anchor>,
  966        click_position: gpui::Point<Pixels>,
  967        mouse_down_time: Instant,
  968    },
  969    /// State when the mouse is dragging the selection in the editor.
  970    Dragging {
  971        selection: Selection<Anchor>,
  972        drop_cursor: Selection<Anchor>,
  973        hide_drop_cursor: bool,
  974    },
  975}
  976
  977enum ColumnarSelectionState {
  978    FromMouse {
  979        selection_tail: Anchor,
  980        display_point: Option<DisplayPoint>,
  981    },
  982    FromSelection {
  983        selection_tail: Anchor,
  984    },
  985}
  986
  987/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  988/// a breakpoint on them.
  989#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  990struct PhantomBreakpointIndicator {
  991    display_row: DisplayRow,
  992    /// There's a small debounce between hovering over the line and showing the indicator.
  993    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  994    is_active: bool,
  995    collides_with_existing_breakpoint: bool,
  996}
  997
  998/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  999///
 1000/// See the [module level documentation](self) for more information.
 1001pub struct Editor {
 1002    focus_handle: FocusHandle,
 1003    last_focused_descendant: Option<WeakFocusHandle>,
 1004    /// The text buffer being edited
 1005    buffer: Entity<MultiBuffer>,
 1006    /// Map of how text in the buffer should be displayed.
 1007    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1008    pub display_map: Entity<DisplayMap>,
 1009    placeholder_display_map: Option<Entity<DisplayMap>>,
 1010    pub selections: SelectionsCollection,
 1011    pub scroll_manager: ScrollManager,
 1012    /// When inline assist editors are linked, they all render cursors because
 1013    /// typing enters text into each of them, even the ones that aren't focused.
 1014    pub(crate) show_cursor_when_unfocused: bool,
 1015    columnar_selection_state: Option<ColumnarSelectionState>,
 1016    add_selections_state: Option<AddSelectionsState>,
 1017    select_next_state: Option<SelectNextState>,
 1018    select_prev_state: Option<SelectNextState>,
 1019    selection_history: SelectionHistory,
 1020    defer_selection_effects: bool,
 1021    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1022    autoclose_regions: Vec<AutocloseRegion>,
 1023    snippet_stack: InvalidationStack<SnippetState>,
 1024    select_syntax_node_history: SelectSyntaxNodeHistory,
 1025    ime_transaction: Option<TransactionId>,
 1026    pub diagnostics_max_severity: DiagnosticSeverity,
 1027    active_diagnostics: ActiveDiagnostic,
 1028    show_inline_diagnostics: bool,
 1029    inline_diagnostics_update: Task<()>,
 1030    inline_diagnostics_enabled: bool,
 1031    diagnostics_enabled: bool,
 1032    word_completions_enabled: bool,
 1033    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1034    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1035    hard_wrap: Option<usize>,
 1036    project: Option<Entity<Project>>,
 1037    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1038    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1039    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1040    blink_manager: Entity<BlinkManager>,
 1041    show_cursor_names: bool,
 1042    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1043    pub show_local_selections: bool,
 1044    mode: EditorMode,
 1045    show_breadcrumbs: bool,
 1046    show_gutter: bool,
 1047    show_scrollbars: ScrollbarAxes,
 1048    minimap_visibility: MinimapVisibility,
 1049    offset_content: bool,
 1050    disable_expand_excerpt_buttons: bool,
 1051    show_line_numbers: Option<bool>,
 1052    use_relative_line_numbers: Option<bool>,
 1053    show_git_diff_gutter: Option<bool>,
 1054    show_code_actions: Option<bool>,
 1055    show_runnables: Option<bool>,
 1056    show_breakpoints: Option<bool>,
 1057    show_wrap_guides: Option<bool>,
 1058    show_indent_guides: Option<bool>,
 1059    highlight_order: usize,
 1060    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1061    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1062    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1063    scrollbar_marker_state: ScrollbarMarkerState,
 1064    active_indent_guides_state: ActiveIndentGuidesState,
 1065    nav_history: Option<ItemNavHistory>,
 1066    context_menu: RefCell<Option<CodeContextMenu>>,
 1067    context_menu_options: Option<ContextMenuOptions>,
 1068    mouse_context_menu: Option<MouseContextMenu>,
 1069    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1070    inline_blame_popover: Option<InlineBlamePopover>,
 1071    inline_blame_popover_show_task: Option<Task<()>>,
 1072    signature_help_state: SignatureHelpState,
 1073    auto_signature_help: Option<bool>,
 1074    find_all_references_task_sources: Vec<Anchor>,
 1075    next_completion_id: CompletionId,
 1076    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1077    code_actions_task: Option<Task<Result<()>>>,
 1078    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1079    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1080    document_highlights_task: Option<Task<()>>,
 1081    linked_editing_range_task: Option<Task<Option<()>>>,
 1082    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1083    pending_rename: Option<RenameState>,
 1084    searchable: bool,
 1085    cursor_shape: CursorShape,
 1086    current_line_highlight: Option<CurrentLineHighlight>,
 1087    collapse_matches: bool,
 1088    autoindent_mode: Option<AutoindentMode>,
 1089    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1090    input_enabled: bool,
 1091    use_modal_editing: bool,
 1092    read_only: bool,
 1093    leader_id: Option<CollaboratorId>,
 1094    remote_id: Option<ViewId>,
 1095    pub hover_state: HoverState,
 1096    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1097    gutter_hovered: bool,
 1098    hovered_link_state: Option<HoveredLinkState>,
 1099    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1100    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1101    active_edit_prediction: Option<EditPredictionState>,
 1102    /// Used to prevent flickering as the user types while the menu is open
 1103    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1104    edit_prediction_settings: EditPredictionSettings,
 1105    edit_predictions_hidden_for_vim_mode: bool,
 1106    show_edit_predictions_override: Option<bool>,
 1107    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1108    edit_prediction_preview: EditPredictionPreview,
 1109    edit_prediction_indent_conflict: bool,
 1110    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1111    inlay_hint_cache: InlayHintCache,
 1112    next_inlay_id: usize,
 1113    _subscriptions: Vec<Subscription>,
 1114    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1115    gutter_dimensions: GutterDimensions,
 1116    style: Option<EditorStyle>,
 1117    text_style_refinement: Option<TextStyleRefinement>,
 1118    next_editor_action_id: EditorActionId,
 1119    editor_actions: Rc<
 1120        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1121    >,
 1122    use_autoclose: bool,
 1123    use_auto_surround: bool,
 1124    auto_replace_emoji_shortcode: bool,
 1125    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1126    show_git_blame_gutter: bool,
 1127    show_git_blame_inline: bool,
 1128    show_git_blame_inline_delay_task: Option<Task<()>>,
 1129    git_blame_inline_enabled: bool,
 1130    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1131    serialize_dirty_buffers: bool,
 1132    show_selection_menu: Option<bool>,
 1133    blame: Option<Entity<GitBlame>>,
 1134    blame_subscription: Option<Subscription>,
 1135    custom_context_menu: Option<
 1136        Box<
 1137            dyn 'static
 1138                + Fn(
 1139                    &mut Self,
 1140                    DisplayPoint,
 1141                    &mut Window,
 1142                    &mut Context<Self>,
 1143                ) -> Option<Entity<ui::ContextMenu>>,
 1144        >,
 1145    >,
 1146    last_bounds: Option<Bounds<Pixels>>,
 1147    last_position_map: Option<Rc<PositionMap>>,
 1148    expect_bounds_change: Option<Bounds<Pixels>>,
 1149    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1150    tasks_update_task: Option<Task<()>>,
 1151    breakpoint_store: Option<Entity<BreakpointStore>>,
 1152    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1153    hovered_diff_hunk_row: Option<DisplayRow>,
 1154    pull_diagnostics_task: Task<()>,
 1155    in_project_search: bool,
 1156    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1157    breadcrumb_header: Option<String>,
 1158    focused_block: Option<FocusedBlock>,
 1159    next_scroll_position: NextScrollCursorCenterTopBottom,
 1160    addons: HashMap<TypeId, Box<dyn Addon>>,
 1161    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1162    load_diff_task: Option<Shared<Task<()>>>,
 1163    /// Whether we are temporarily displaying a diff other than git's
 1164    temporary_diff_override: bool,
 1165    selection_mark_mode: bool,
 1166    toggle_fold_multiple_buffers: Task<()>,
 1167    _scroll_cursor_center_top_bottom_task: Task<()>,
 1168    serialize_selections: Task<()>,
 1169    serialize_folds: Task<()>,
 1170    mouse_cursor_hidden: bool,
 1171    minimap: Option<Entity<Self>>,
 1172    hide_mouse_mode: HideMouseMode,
 1173    pub change_list: ChangeList,
 1174    inline_value_cache: InlineValueCache,
 1175    selection_drag_state: SelectionDragState,
 1176    next_color_inlay_id: usize,
 1177    colors: Option<LspColorData>,
 1178    folding_newlines: Task<()>,
 1179    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1180}
 1181
 1182#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1183enum NextScrollCursorCenterTopBottom {
 1184    #[default]
 1185    Center,
 1186    Top,
 1187    Bottom,
 1188}
 1189
 1190impl NextScrollCursorCenterTopBottom {
 1191    fn next(&self) -> Self {
 1192        match self {
 1193            Self::Center => Self::Top,
 1194            Self::Top => Self::Bottom,
 1195            Self::Bottom => Self::Center,
 1196        }
 1197    }
 1198}
 1199
 1200#[derive(Clone)]
 1201pub struct EditorSnapshot {
 1202    pub mode: EditorMode,
 1203    show_gutter: bool,
 1204    show_line_numbers: Option<bool>,
 1205    show_git_diff_gutter: Option<bool>,
 1206    show_code_actions: Option<bool>,
 1207    show_runnables: Option<bool>,
 1208    show_breakpoints: Option<bool>,
 1209    git_blame_gutter_max_author_length: Option<usize>,
 1210    pub display_snapshot: DisplaySnapshot,
 1211    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1212    is_focused: bool,
 1213    scroll_anchor: ScrollAnchor,
 1214    ongoing_scroll: OngoingScroll,
 1215    current_line_highlight: CurrentLineHighlight,
 1216    gutter_hovered: bool,
 1217}
 1218
 1219#[derive(Default, Debug, Clone, Copy)]
 1220pub struct GutterDimensions {
 1221    pub left_padding: Pixels,
 1222    pub right_padding: Pixels,
 1223    pub width: Pixels,
 1224    pub margin: Pixels,
 1225    pub git_blame_entries_width: Option<Pixels>,
 1226}
 1227
 1228impl GutterDimensions {
 1229    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1230        Self {
 1231            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1232            ..Default::default()
 1233        }
 1234    }
 1235
 1236    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1237        -cx.text_system().descent(font_id, font_size)
 1238    }
 1239    /// The full width of the space taken up by the gutter.
 1240    pub fn full_width(&self) -> Pixels {
 1241        self.margin + self.width
 1242    }
 1243
 1244    /// The width of the space reserved for the fold indicators,
 1245    /// use alongside 'justify_end' and `gutter_width` to
 1246    /// right align content with the line numbers
 1247    pub fn fold_area_width(&self) -> Pixels {
 1248        self.margin + self.right_padding
 1249    }
 1250}
 1251
 1252struct CharacterDimensions {
 1253    em_width: Pixels,
 1254    em_advance: Pixels,
 1255    line_height: Pixels,
 1256}
 1257
 1258#[derive(Debug)]
 1259pub struct RemoteSelection {
 1260    pub replica_id: ReplicaId,
 1261    pub selection: Selection<Anchor>,
 1262    pub cursor_shape: CursorShape,
 1263    pub collaborator_id: CollaboratorId,
 1264    pub line_mode: bool,
 1265    pub user_name: Option<SharedString>,
 1266    pub color: PlayerColor,
 1267}
 1268
 1269#[derive(Clone, Debug)]
 1270struct SelectionHistoryEntry {
 1271    selections: Arc<[Selection<Anchor>]>,
 1272    select_next_state: Option<SelectNextState>,
 1273    select_prev_state: Option<SelectNextState>,
 1274    add_selections_state: Option<AddSelectionsState>,
 1275}
 1276
 1277#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1278enum SelectionHistoryMode {
 1279    Normal,
 1280    Undoing,
 1281    Redoing,
 1282    Skipping,
 1283}
 1284
 1285#[derive(Clone, PartialEq, Eq, Hash)]
 1286struct HoveredCursor {
 1287    replica_id: u16,
 1288    selection_id: usize,
 1289}
 1290
 1291impl Default for SelectionHistoryMode {
 1292    fn default() -> Self {
 1293        Self::Normal
 1294    }
 1295}
 1296
 1297#[derive(Debug)]
 1298/// SelectionEffects controls the side-effects of updating the selection.
 1299///
 1300/// The default behaviour does "what you mostly want":
 1301/// - it pushes to the nav history if the cursor moved by >10 lines
 1302/// - it re-triggers completion requests
 1303/// - it scrolls to fit
 1304///
 1305/// You might want to modify these behaviours. For example when doing a "jump"
 1306/// like go to definition, we always want to add to nav history; but when scrolling
 1307/// in vim mode we never do.
 1308///
 1309/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1310/// move.
 1311#[derive(Clone)]
 1312pub struct SelectionEffects {
 1313    nav_history: Option<bool>,
 1314    completions: bool,
 1315    scroll: Option<Autoscroll>,
 1316}
 1317
 1318impl Default for SelectionEffects {
 1319    fn default() -> Self {
 1320        Self {
 1321            nav_history: None,
 1322            completions: true,
 1323            scroll: Some(Autoscroll::fit()),
 1324        }
 1325    }
 1326}
 1327impl SelectionEffects {
 1328    pub fn scroll(scroll: Autoscroll) -> Self {
 1329        Self {
 1330            scroll: Some(scroll),
 1331            ..Default::default()
 1332        }
 1333    }
 1334
 1335    pub fn no_scroll() -> Self {
 1336        Self {
 1337            scroll: None,
 1338            ..Default::default()
 1339        }
 1340    }
 1341
 1342    pub fn completions(self, completions: bool) -> Self {
 1343        Self {
 1344            completions,
 1345            ..self
 1346        }
 1347    }
 1348
 1349    pub fn nav_history(self, nav_history: bool) -> Self {
 1350        Self {
 1351            nav_history: Some(nav_history),
 1352            ..self
 1353        }
 1354    }
 1355}
 1356
 1357struct DeferredSelectionEffectsState {
 1358    changed: bool,
 1359    effects: SelectionEffects,
 1360    old_cursor_position: Anchor,
 1361    history_entry: SelectionHistoryEntry,
 1362}
 1363
 1364#[derive(Default)]
 1365struct SelectionHistory {
 1366    #[allow(clippy::type_complexity)]
 1367    selections_by_transaction:
 1368        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1369    mode: SelectionHistoryMode,
 1370    undo_stack: VecDeque<SelectionHistoryEntry>,
 1371    redo_stack: VecDeque<SelectionHistoryEntry>,
 1372}
 1373
 1374impl SelectionHistory {
 1375    #[track_caller]
 1376    fn insert_transaction(
 1377        &mut self,
 1378        transaction_id: TransactionId,
 1379        selections: Arc<[Selection<Anchor>]>,
 1380    ) {
 1381        if selections.is_empty() {
 1382            log::error!(
 1383                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1384                std::panic::Location::caller()
 1385            );
 1386            return;
 1387        }
 1388        self.selections_by_transaction
 1389            .insert(transaction_id, (selections, None));
 1390    }
 1391
 1392    #[allow(clippy::type_complexity)]
 1393    fn transaction(
 1394        &self,
 1395        transaction_id: TransactionId,
 1396    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1397        self.selections_by_transaction.get(&transaction_id)
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction_mut(
 1402        &mut self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get_mut(&transaction_id)
 1406    }
 1407
 1408    fn push(&mut self, entry: SelectionHistoryEntry) {
 1409        if !entry.selections.is_empty() {
 1410            match self.mode {
 1411                SelectionHistoryMode::Normal => {
 1412                    self.push_undo(entry);
 1413                    self.redo_stack.clear();
 1414                }
 1415                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1416                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1417                SelectionHistoryMode::Skipping => {}
 1418            }
 1419        }
 1420    }
 1421
 1422    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1423        if self
 1424            .undo_stack
 1425            .back()
 1426            .is_none_or(|e| e.selections != entry.selections)
 1427        {
 1428            self.undo_stack.push_back(entry);
 1429            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1430                self.undo_stack.pop_front();
 1431            }
 1432        }
 1433    }
 1434
 1435    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1436        if self
 1437            .redo_stack
 1438            .back()
 1439            .is_none_or(|e| e.selections != entry.selections)
 1440        {
 1441            self.redo_stack.push_back(entry);
 1442            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1443                self.redo_stack.pop_front();
 1444            }
 1445        }
 1446    }
 1447}
 1448
 1449#[derive(Clone, Copy)]
 1450pub struct RowHighlightOptions {
 1451    pub autoscroll: bool,
 1452    pub include_gutter: bool,
 1453}
 1454
 1455impl Default for RowHighlightOptions {
 1456    fn default() -> Self {
 1457        Self {
 1458            autoscroll: Default::default(),
 1459            include_gutter: true,
 1460        }
 1461    }
 1462}
 1463
 1464struct RowHighlight {
 1465    index: usize,
 1466    range: Range<Anchor>,
 1467    color: Hsla,
 1468    options: RowHighlightOptions,
 1469    type_id: TypeId,
 1470}
 1471
 1472#[derive(Clone, Debug)]
 1473struct AddSelectionsState {
 1474    groups: Vec<AddSelectionsGroup>,
 1475}
 1476
 1477#[derive(Clone, Debug)]
 1478struct AddSelectionsGroup {
 1479    above: bool,
 1480    stack: Vec<usize>,
 1481}
 1482
 1483#[derive(Clone)]
 1484struct SelectNextState {
 1485    query: AhoCorasick,
 1486    wordwise: bool,
 1487    done: bool,
 1488}
 1489
 1490impl std::fmt::Debug for SelectNextState {
 1491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1492        f.debug_struct(std::any::type_name::<Self>())
 1493            .field("wordwise", &self.wordwise)
 1494            .field("done", &self.done)
 1495            .finish()
 1496    }
 1497}
 1498
 1499#[derive(Debug)]
 1500struct AutocloseRegion {
 1501    selection_id: usize,
 1502    range: Range<Anchor>,
 1503    pair: BracketPair,
 1504}
 1505
 1506#[derive(Debug)]
 1507struct SnippetState {
 1508    ranges: Vec<Vec<Range<Anchor>>>,
 1509    active_index: usize,
 1510    choices: Vec<Option<Vec<String>>>,
 1511}
 1512
 1513#[doc(hidden)]
 1514pub struct RenameState {
 1515    pub range: Range<Anchor>,
 1516    pub old_name: Arc<str>,
 1517    pub editor: Entity<Editor>,
 1518    block_id: CustomBlockId,
 1519}
 1520
 1521struct InvalidationStack<T>(Vec<T>);
 1522
 1523struct RegisteredEditPredictionProvider {
 1524    provider: Arc<dyn EditPredictionProviderHandle>,
 1525    _subscription: Subscription,
 1526}
 1527
 1528#[derive(Debug, PartialEq, Eq)]
 1529pub struct ActiveDiagnosticGroup {
 1530    pub active_range: Range<Anchor>,
 1531    pub active_message: String,
 1532    pub group_id: usize,
 1533    pub blocks: HashSet<CustomBlockId>,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537
 1538pub(crate) enum ActiveDiagnostic {
 1539    None,
 1540    All,
 1541    Group(ActiveDiagnosticGroup),
 1542}
 1543
 1544#[derive(Serialize, Deserialize, Clone, Debug)]
 1545pub struct ClipboardSelection {
 1546    /// The number of bytes in this selection.
 1547    pub len: usize,
 1548    /// Whether this was a full-line selection.
 1549    pub is_entire_line: bool,
 1550    /// The indentation of the first line when this content was originally copied.
 1551    pub first_line_indent: u32,
 1552}
 1553
 1554// selections, scroll behavior, was newest selection reversed
 1555type SelectSyntaxNodeHistoryState = (
 1556    Box<[Selection<usize>]>,
 1557    SelectSyntaxNodeScrollBehavior,
 1558    bool,
 1559);
 1560
 1561#[derive(Default)]
 1562struct SelectSyntaxNodeHistory {
 1563    stack: Vec<SelectSyntaxNodeHistoryState>,
 1564    // disable temporarily to allow changing selections without losing the stack
 1565    pub disable_clearing: bool,
 1566}
 1567
 1568impl SelectSyntaxNodeHistory {
 1569    pub fn try_clear(&mut self) {
 1570        if !self.disable_clearing {
 1571            self.stack.clear();
 1572        }
 1573    }
 1574
 1575    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1576        self.stack.push(selection);
 1577    }
 1578
 1579    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1580        self.stack.pop()
 1581    }
 1582}
 1583
 1584enum SelectSyntaxNodeScrollBehavior {
 1585    CursorTop,
 1586    FitSelection,
 1587    CursorBottom,
 1588}
 1589
 1590#[derive(Debug)]
 1591pub(crate) struct NavigationData {
 1592    cursor_anchor: Anchor,
 1593    cursor_position: Point,
 1594    scroll_anchor: ScrollAnchor,
 1595    scroll_top_row: u32,
 1596}
 1597
 1598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1599pub enum GotoDefinitionKind {
 1600    Symbol,
 1601    Declaration,
 1602    Type,
 1603    Implementation,
 1604}
 1605
 1606#[derive(Debug, Clone)]
 1607enum InlayHintRefreshReason {
 1608    ModifiersChanged(bool),
 1609    Toggle(bool),
 1610    SettingsChange(InlayHintSettings),
 1611    NewLinesShown,
 1612    BufferEdited(HashSet<Arc<Language>>),
 1613    RefreshRequested,
 1614    ExcerptsRemoved(Vec<ExcerptId>),
 1615}
 1616
 1617impl InlayHintRefreshReason {
 1618    fn description(&self) -> &'static str {
 1619        match self {
 1620            Self::ModifiersChanged(_) => "modifiers changed",
 1621            Self::Toggle(_) => "toggle",
 1622            Self::SettingsChange(_) => "settings change",
 1623            Self::NewLinesShown => "new lines shown",
 1624            Self::BufferEdited(_) => "buffer edited",
 1625            Self::RefreshRequested => "refresh requested",
 1626            Self::ExcerptsRemoved(_) => "excerpts removed",
 1627        }
 1628    }
 1629}
 1630
 1631pub enum FormatTarget {
 1632    Buffers(HashSet<Entity<Buffer>>),
 1633    Ranges(Vec<Range<MultiBufferPoint>>),
 1634}
 1635
 1636pub(crate) struct FocusedBlock {
 1637    id: BlockId,
 1638    focus_handle: WeakFocusHandle,
 1639}
 1640
 1641#[derive(Clone)]
 1642enum JumpData {
 1643    MultiBufferRow {
 1644        row: MultiBufferRow,
 1645        line_offset_from_top: u32,
 1646    },
 1647    MultiBufferPoint {
 1648        excerpt_id: ExcerptId,
 1649        position: Point,
 1650        anchor: text::Anchor,
 1651        line_offset_from_top: u32,
 1652    },
 1653}
 1654
 1655pub enum MultibufferSelectionMode {
 1656    First,
 1657    All,
 1658}
 1659
 1660#[derive(Clone, Copy, Debug, Default)]
 1661pub struct RewrapOptions {
 1662    pub override_language_settings: bool,
 1663    pub preserve_existing_whitespace: bool,
 1664}
 1665
 1666impl Editor {
 1667    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1671    }
 1672
 1673    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::full(), buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn auto_height(
 1680        min_lines: usize,
 1681        max_lines: usize,
 1682        window: &mut Window,
 1683        cx: &mut Context<Self>,
 1684    ) -> Self {
 1685        let buffer = cx.new(|cx| Buffer::local("", cx));
 1686        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1687        Self::new(
 1688            EditorMode::AutoHeight {
 1689                min_lines,
 1690                max_lines: Some(max_lines),
 1691            },
 1692            buffer,
 1693            None,
 1694            window,
 1695            cx,
 1696        )
 1697    }
 1698
 1699    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1700    /// The editor grows as tall as needed to fit its content.
 1701    pub fn auto_height_unbounded(
 1702        min_lines: usize,
 1703        window: &mut Window,
 1704        cx: &mut Context<Self>,
 1705    ) -> Self {
 1706        let buffer = cx.new(|cx| Buffer::local("", cx));
 1707        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1708        Self::new(
 1709            EditorMode::AutoHeight {
 1710                min_lines,
 1711                max_lines: None,
 1712            },
 1713            buffer,
 1714            None,
 1715            window,
 1716            cx,
 1717        )
 1718    }
 1719
 1720    pub fn for_buffer(
 1721        buffer: Entity<Buffer>,
 1722        project: Option<Entity<Project>>,
 1723        window: &mut Window,
 1724        cx: &mut Context<Self>,
 1725    ) -> Self {
 1726        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1727        Self::new(EditorMode::full(), buffer, project, window, cx)
 1728    }
 1729
 1730    pub fn for_multibuffer(
 1731        buffer: Entity<MultiBuffer>,
 1732        project: Option<Entity<Project>>,
 1733        window: &mut Window,
 1734        cx: &mut Context<Self>,
 1735    ) -> Self {
 1736        Self::new(EditorMode::full(), buffer, project, window, cx)
 1737    }
 1738
 1739    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1740        let mut clone = Self::new(
 1741            self.mode.clone(),
 1742            self.buffer.clone(),
 1743            self.project.clone(),
 1744            window,
 1745            cx,
 1746        );
 1747        self.display_map.update(cx, |display_map, cx| {
 1748            let snapshot = display_map.snapshot(cx);
 1749            clone.display_map.update(cx, |display_map, cx| {
 1750                display_map.set_state(&snapshot, cx);
 1751            });
 1752        });
 1753        clone.folds_did_change(cx);
 1754        clone.selections.clone_state(&self.selections);
 1755        clone.scroll_manager.clone_state(&self.scroll_manager);
 1756        clone.searchable = self.searchable;
 1757        clone.read_only = self.read_only;
 1758        clone
 1759    }
 1760
 1761    pub fn new(
 1762        mode: EditorMode,
 1763        buffer: Entity<MultiBuffer>,
 1764        project: Option<Entity<Project>>,
 1765        window: &mut Window,
 1766        cx: &mut Context<Self>,
 1767    ) -> Self {
 1768        Editor::new_internal(mode, buffer, project, None, window, cx)
 1769    }
 1770
 1771    fn new_internal(
 1772        mode: EditorMode,
 1773        buffer: Entity<MultiBuffer>,
 1774        project: Option<Entity<Project>>,
 1775        display_map: Option<Entity<DisplayMap>>,
 1776        window: &mut Window,
 1777        cx: &mut Context<Self>,
 1778    ) -> Self {
 1779        debug_assert!(
 1780            display_map.is_none() || mode.is_minimap(),
 1781            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1782        );
 1783
 1784        let full_mode = mode.is_full();
 1785        let is_minimap = mode.is_minimap();
 1786        let diagnostics_max_severity = if full_mode {
 1787            EditorSettings::get_global(cx)
 1788                .diagnostics_max_severity
 1789                .unwrap_or(DiagnosticSeverity::Hint)
 1790        } else {
 1791            DiagnosticSeverity::Off
 1792        };
 1793        let style = window.text_style();
 1794        let font_size = style.font_size.to_pixels(window.rem_size());
 1795        let editor = cx.entity().downgrade();
 1796        let fold_placeholder = FoldPlaceholder {
 1797            constrain_width: false,
 1798            render: Arc::new(move |fold_id, fold_range, cx| {
 1799                let editor = editor.clone();
 1800                div()
 1801                    .id(fold_id)
 1802                    .bg(cx.theme().colors().ghost_element_background)
 1803                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1804                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1805                    .rounded_xs()
 1806                    .size_full()
 1807                    .cursor_pointer()
 1808                    .child("")
 1809                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1810                    .on_click(move |_, _window, cx| {
 1811                        editor
 1812                            .update(cx, |editor, cx| {
 1813                                editor.unfold_ranges(
 1814                                    &[fold_range.start..fold_range.end],
 1815                                    true,
 1816                                    false,
 1817                                    cx,
 1818                                );
 1819                                cx.stop_propagation();
 1820                            })
 1821                            .ok();
 1822                    })
 1823                    .into_any()
 1824            }),
 1825            merge_adjacent: true,
 1826            ..FoldPlaceholder::default()
 1827        };
 1828        let display_map = display_map.unwrap_or_else(|| {
 1829            cx.new(|cx| {
 1830                DisplayMap::new(
 1831                    buffer.clone(),
 1832                    style.font(),
 1833                    font_size,
 1834                    None,
 1835                    FILE_HEADER_HEIGHT,
 1836                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1837                    fold_placeholder,
 1838                    diagnostics_max_severity,
 1839                    cx,
 1840                )
 1841            })
 1842        });
 1843
 1844        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1845
 1846        let blink_manager = cx.new(|cx| {
 1847            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1848            if is_minimap {
 1849                blink_manager.disable(cx);
 1850            }
 1851            blink_manager
 1852        });
 1853
 1854        let soft_wrap_mode_override =
 1855            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1856
 1857        let mut project_subscriptions = Vec::new();
 1858        if full_mode && let Some(project) = project.as_ref() {
 1859            project_subscriptions.push(cx.subscribe_in(
 1860                project,
 1861                window,
 1862                |editor, _, event, window, cx| match event {
 1863                    project::Event::RefreshCodeLens => {
 1864                        // we always query lens with actions, without storing them, always refreshing them
 1865                    }
 1866                    project::Event::RefreshInlayHints => {
 1867                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1868                    }
 1869                    project::Event::LanguageServerAdded(..)
 1870                    | project::Event::LanguageServerRemoved(..) => {
 1871                        if editor.tasks_update_task.is_none() {
 1872                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1873                        }
 1874                    }
 1875                    project::Event::SnippetEdit(id, snippet_edits) => {
 1876                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1877                            let focus_handle = editor.focus_handle(cx);
 1878                            if focus_handle.is_focused(window) {
 1879                                let snapshot = buffer.read(cx).snapshot();
 1880                                for (range, snippet) in snippet_edits {
 1881                                    let editor_range =
 1882                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1883                                    editor
 1884                                        .insert_snippet(
 1885                                            &[editor_range],
 1886                                            snippet.clone(),
 1887                                            window,
 1888                                            cx,
 1889                                        )
 1890                                        .ok();
 1891                                }
 1892                            }
 1893                        }
 1894                    }
 1895                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1896                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1897                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1898                        }
 1899                    }
 1900
 1901                    project::Event::EntryRenamed(transaction) => {
 1902                        let Some(workspace) = editor.workspace() else {
 1903                            return;
 1904                        };
 1905                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1906                        else {
 1907                            return;
 1908                        };
 1909                        if active_editor.entity_id() == cx.entity_id() {
 1910                            let edited_buffers_already_open = {
 1911                                let other_editors: Vec<Entity<Editor>> = workspace
 1912                                    .read(cx)
 1913                                    .panes()
 1914                                    .iter()
 1915                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1916                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1917                                    .collect();
 1918
 1919                                transaction.0.keys().all(|buffer| {
 1920                                    other_editors.iter().any(|editor| {
 1921                                        let multi_buffer = editor.read(cx).buffer();
 1922                                        multi_buffer.read(cx).is_singleton()
 1923                                            && multi_buffer.read(cx).as_singleton().map_or(
 1924                                                false,
 1925                                                |singleton| {
 1926                                                    singleton.entity_id() == buffer.entity_id()
 1927                                                },
 1928                                            )
 1929                                    })
 1930                                })
 1931                            };
 1932
 1933                            if !edited_buffers_already_open {
 1934                                let workspace = workspace.downgrade();
 1935                                let transaction = transaction.clone();
 1936                                cx.defer_in(window, move |_, window, cx| {
 1937                                    cx.spawn_in(window, async move |editor, cx| {
 1938                                        Self::open_project_transaction(
 1939                                            &editor,
 1940                                            workspace,
 1941                                            transaction,
 1942                                            "Rename".to_string(),
 1943                                            cx,
 1944                                        )
 1945                                        .await
 1946                                        .ok()
 1947                                    })
 1948                                    .detach();
 1949                                });
 1950                            }
 1951                        }
 1952                    }
 1953
 1954                    _ => {}
 1955                },
 1956            ));
 1957            if let Some(task_inventory) = project
 1958                .read(cx)
 1959                .task_store()
 1960                .read(cx)
 1961                .task_inventory()
 1962                .cloned()
 1963            {
 1964                project_subscriptions.push(cx.observe_in(
 1965                    &task_inventory,
 1966                    window,
 1967                    |editor, _, window, cx| {
 1968                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1969                    },
 1970                ));
 1971            };
 1972
 1973            project_subscriptions.push(cx.subscribe_in(
 1974                &project.read(cx).breakpoint_store(),
 1975                window,
 1976                |editor, _, event, window, cx| match event {
 1977                    BreakpointStoreEvent::ClearDebugLines => {
 1978                        editor.clear_row_highlights::<ActiveDebugLine>();
 1979                        editor.refresh_inline_values(cx);
 1980                    }
 1981                    BreakpointStoreEvent::SetDebugLine => {
 1982                        if editor.go_to_active_debug_line(window, cx) {
 1983                            cx.stop_propagation();
 1984                        }
 1985
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    _ => {}
 1989                },
 1990            ));
 1991            let git_store = project.read(cx).git_store().clone();
 1992            let project = project.clone();
 1993            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1994                if let GitStoreEvent::RepositoryUpdated(
 1995                    _,
 1996                    RepositoryEvent::Updated {
 1997                        new_instance: true, ..
 1998                    },
 1999                    _,
 2000                ) = event
 2001                {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    buffer.read(cx).all_buffers(),
 2054                    buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            placeholder_display_map: None,
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144            collapse_matches: false,
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            word_completions_enabled: full_mode,
 2167            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2168            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2169            gutter_hovered: false,
 2170            pixel_position_of_newest_cursor: None,
 2171            last_bounds: None,
 2172            last_position_map: None,
 2173            expect_bounds_change: None,
 2174            gutter_dimensions: GutterDimensions::default(),
 2175            style: None,
 2176            show_cursor_names: false,
 2177            hovered_cursors: HashMap::default(),
 2178            next_editor_action_id: EditorActionId::default(),
 2179            editor_actions: Rc::default(),
 2180            edit_predictions_hidden_for_vim_mode: false,
 2181            show_edit_predictions_override: None,
 2182            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2183            edit_prediction_settings: EditPredictionSettings::Disabled,
 2184            edit_prediction_indent_conflict: false,
 2185            edit_prediction_requires_modifier_in_indent_conflict: true,
 2186            custom_context_menu: None,
 2187            show_git_blame_gutter: false,
 2188            show_git_blame_inline: false,
 2189            show_selection_menu: None,
 2190            show_git_blame_inline_delay_task: None,
 2191            git_blame_inline_enabled: full_mode
 2192                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2193            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2194            serialize_dirty_buffers: !is_minimap
 2195                && ProjectSettings::get_global(cx)
 2196                    .session
 2197                    .restore_unsaved_buffers,
 2198            blame: None,
 2199            blame_subscription: None,
 2200            tasks: BTreeMap::default(),
 2201
 2202            breakpoint_store,
 2203            gutter_breakpoint_indicator: (None, None),
 2204            hovered_diff_hunk_row: None,
 2205            _subscriptions: (!is_minimap)
 2206                .then(|| {
 2207                    vec![
 2208                        cx.observe(&buffer, Self::on_buffer_changed),
 2209                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2210                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2211                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2212                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2213                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2214                        cx.observe_window_activation(window, |editor, window, cx| {
 2215                            let active = window.is_window_active();
 2216                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2217                                if active {
 2218                                    blink_manager.enable(cx);
 2219                                } else {
 2220                                    blink_manager.disable(cx);
 2221                                }
 2222                            });
 2223                            if active {
 2224                                editor.show_mouse_cursor(cx);
 2225                            }
 2226                        }),
 2227                    ]
 2228                })
 2229                .unwrap_or_default(),
 2230            tasks_update_task: None,
 2231            pull_diagnostics_task: Task::ready(()),
 2232            colors: None,
 2233            next_color_inlay_id: 0,
 2234            linked_edit_ranges: Default::default(),
 2235            in_project_search: false,
 2236            previous_search_ranges: None,
 2237            breadcrumb_header: None,
 2238            focused_block: None,
 2239            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2240            addons: HashMap::default(),
 2241            registered_buffers: HashMap::default(),
 2242            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2243            selection_mark_mode: false,
 2244            toggle_fold_multiple_buffers: Task::ready(()),
 2245            serialize_selections: Task::ready(()),
 2246            serialize_folds: Task::ready(()),
 2247            text_style_refinement: None,
 2248            load_diff_task: load_uncommitted_diff,
 2249            temporary_diff_override: false,
 2250            mouse_cursor_hidden: false,
 2251            minimap: None,
 2252            hide_mouse_mode: EditorSettings::get_global(cx)
 2253                .hide_mouse
 2254                .unwrap_or_default(),
 2255            change_list: ChangeList::new(),
 2256            mode,
 2257            selection_drag_state: SelectionDragState::None,
 2258            folding_newlines: Task::ready(()),
 2259            lookup_key: None,
 2260        };
 2261
 2262        if is_minimap {
 2263            return editor;
 2264        }
 2265
 2266        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2267            editor
 2268                ._subscriptions
 2269                .push(cx.observe(breakpoints, |_, _, cx| {
 2270                    cx.notify();
 2271                }));
 2272        }
 2273        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2274        editor._subscriptions.extend(project_subscriptions);
 2275
 2276        editor._subscriptions.push(cx.subscribe_in(
 2277            &cx.entity(),
 2278            window,
 2279            |editor, _, e: &EditorEvent, window, cx| match e {
 2280                EditorEvent::ScrollPositionChanged { local, .. } => {
 2281                    if *local {
 2282                        let new_anchor = editor.scroll_manager.anchor();
 2283                        let snapshot = editor.snapshot(window, cx);
 2284                        editor.update_restoration_data(cx, move |data| {
 2285                            data.scroll_position = (
 2286                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2287                                new_anchor.offset,
 2288                            );
 2289                        });
 2290                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2291                        editor.inline_blame_popover.take();
 2292                    }
 2293                }
 2294                EditorEvent::Edited { .. } => {
 2295                    if !vim_enabled(cx) {
 2296                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            if let Some(buffer) = buffer.read(cx).as_singleton()
 2369                && let Some(project) = editor.project()
 2370            {
 2371                let handle = project.update(cx, |project, cx| {
 2372                    project.register_buffer_with_language_servers(&buffer, cx)
 2373                });
 2374                editor
 2375                    .registered_buffers
 2376                    .insert(buffer.read(cx).remote_id(), handle);
 2377            }
 2378
 2379            editor.minimap =
 2380                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2381            editor.colors = Some(LspColorData::new(cx));
 2382            editor.update_lsp_data(false, None, window, cx);
 2383        }
 2384
 2385        if editor.mode.is_full() {
 2386            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2387        }
 2388
 2389        editor
 2390    }
 2391
 2392    pub fn deploy_mouse_context_menu(
 2393        &mut self,
 2394        position: gpui::Point<Pixels>,
 2395        context_menu: Entity<ContextMenu>,
 2396        window: &mut Window,
 2397        cx: &mut Context<Self>,
 2398    ) {
 2399        self.mouse_context_menu = Some(MouseContextMenu::new(
 2400            self,
 2401            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2402            context_menu,
 2403            window,
 2404            cx,
 2405        ));
 2406    }
 2407
 2408    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2409        self.mouse_context_menu
 2410            .as_ref()
 2411            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2412    }
 2413
 2414    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2415        if self
 2416            .selections
 2417            .pending
 2418            .as_ref()
 2419            .is_some_and(|pending_selection| {
 2420                let snapshot = self.buffer().read(cx).snapshot(cx);
 2421                pending_selection
 2422                    .selection
 2423                    .range()
 2424                    .includes(range, &snapshot)
 2425            })
 2426        {
 2427            return true;
 2428        }
 2429
 2430        self.selections
 2431            .disjoint_in_range::<usize>(range.clone(), cx)
 2432            .into_iter()
 2433            .any(|selection| {
 2434                // This is needed to cover a corner case, if we just check for an existing
 2435                // selection in the fold range, having a cursor at the start of the fold
 2436                // marks it as selected. Non-empty selections don't cause this.
 2437                let length = selection.end - selection.start;
 2438                length > 0
 2439            })
 2440    }
 2441
 2442    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2443        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2444    }
 2445
 2446    fn key_context_internal(
 2447        &self,
 2448        has_active_edit_prediction: bool,
 2449        window: &Window,
 2450        cx: &App,
 2451    ) -> KeyContext {
 2452        let mut key_context = KeyContext::new_with_defaults();
 2453        key_context.add("Editor");
 2454        let mode = match self.mode {
 2455            EditorMode::SingleLine => "single_line",
 2456            EditorMode::AutoHeight { .. } => "auto_height",
 2457            EditorMode::Minimap { .. } => "minimap",
 2458            EditorMode::Full { .. } => "full",
 2459        };
 2460
 2461        if EditorSettings::jupyter_enabled(cx) {
 2462            key_context.add("jupyter");
 2463        }
 2464
 2465        key_context.set("mode", mode);
 2466        if self.pending_rename.is_some() {
 2467            key_context.add("renaming");
 2468        }
 2469
 2470        match self.context_menu.borrow().as_ref() {
 2471            Some(CodeContextMenu::Completions(menu)) => {
 2472                if menu.visible() {
 2473                    key_context.add("menu");
 2474                    key_context.add("showing_completions");
 2475                }
 2476            }
 2477            Some(CodeContextMenu::CodeActions(menu)) => {
 2478                if menu.visible() {
 2479                    key_context.add("menu");
 2480                    key_context.add("showing_code_actions")
 2481                }
 2482            }
 2483            None => {}
 2484        }
 2485
 2486        if self.signature_help_state.has_multiple_signatures() {
 2487            key_context.add("showing_signature_help");
 2488        }
 2489
 2490        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2491        if !self.focus_handle(cx).contains_focused(window, cx)
 2492            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2493        {
 2494            for addon in self.addons.values() {
 2495                addon.extend_key_context(&mut key_context, cx)
 2496            }
 2497        }
 2498
 2499        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2500            if let Some(extension) = singleton_buffer
 2501                .read(cx)
 2502                .file()
 2503                .and_then(|file| file.path().extension()?.to_str())
 2504            {
 2505                key_context.set("extension", extension.to_string());
 2506            }
 2507        } else {
 2508            key_context.add("multibuffer");
 2509        }
 2510
 2511        if has_active_edit_prediction {
 2512            if self.edit_prediction_in_conflict() {
 2513                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2514            } else {
 2515                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2516                key_context.add("copilot_suggestion");
 2517            }
 2518        }
 2519
 2520        if self.selection_mark_mode {
 2521            key_context.add("selection_mode");
 2522        }
 2523
 2524        key_context
 2525    }
 2526
 2527    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2528        if self.mouse_cursor_hidden {
 2529            self.mouse_cursor_hidden = false;
 2530            cx.notify();
 2531        }
 2532    }
 2533
 2534    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2535        let hide_mouse_cursor = match origin {
 2536            HideMouseCursorOrigin::TypingAction => {
 2537                matches!(
 2538                    self.hide_mouse_mode,
 2539                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2540                )
 2541            }
 2542            HideMouseCursorOrigin::MovementAction => {
 2543                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2544            }
 2545        };
 2546        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2547            self.mouse_cursor_hidden = hide_mouse_cursor;
 2548            cx.notify();
 2549        }
 2550    }
 2551
 2552    pub fn edit_prediction_in_conflict(&self) -> bool {
 2553        if !self.show_edit_predictions_in_menu() {
 2554            return false;
 2555        }
 2556
 2557        let showing_completions = self
 2558            .context_menu
 2559            .borrow()
 2560            .as_ref()
 2561            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2562
 2563        showing_completions
 2564            || self.edit_prediction_requires_modifier()
 2565            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2566            // bindings to insert tab characters.
 2567            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2568    }
 2569
 2570    pub fn accept_edit_prediction_keybind(
 2571        &self,
 2572        accept_partial: bool,
 2573        window: &Window,
 2574        cx: &App,
 2575    ) -> AcceptEditPredictionBinding {
 2576        let key_context = self.key_context_internal(true, window, cx);
 2577        let in_conflict = self.edit_prediction_in_conflict();
 2578
 2579        let bindings = if accept_partial {
 2580            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2581        } else {
 2582            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2583        };
 2584
 2585        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2586        // just the first one.
 2587        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2588            !in_conflict
 2589                || binding
 2590                    .keystrokes()
 2591                    .first()
 2592                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2593        }))
 2594    }
 2595
 2596    pub fn new_file(
 2597        workspace: &mut Workspace,
 2598        _: &workspace::NewFile,
 2599        window: &mut Window,
 2600        cx: &mut Context<Workspace>,
 2601    ) {
 2602        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2603            "Failed to create buffer",
 2604            window,
 2605            cx,
 2606            |e, _, _| match e.error_code() {
 2607                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2608                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2609                e.error_tag("required").unwrap_or("the latest version")
 2610            )),
 2611                _ => None,
 2612            },
 2613        );
 2614    }
 2615
 2616    pub fn new_in_workspace(
 2617        workspace: &mut Workspace,
 2618        window: &mut Window,
 2619        cx: &mut Context<Workspace>,
 2620    ) -> Task<Result<Entity<Editor>>> {
 2621        let project = workspace.project().clone();
 2622        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2623
 2624        cx.spawn_in(window, async move |workspace, cx| {
 2625            let buffer = create.await?;
 2626            workspace.update_in(cx, |workspace, window, cx| {
 2627                let editor =
 2628                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2629                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2630                editor
 2631            })
 2632        })
 2633    }
 2634
 2635    fn new_file_vertical(
 2636        workspace: &mut Workspace,
 2637        _: &workspace::NewFileSplitVertical,
 2638        window: &mut Window,
 2639        cx: &mut Context<Workspace>,
 2640    ) {
 2641        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2642    }
 2643
 2644    fn new_file_horizontal(
 2645        workspace: &mut Workspace,
 2646        _: &workspace::NewFileSplitHorizontal,
 2647        window: &mut Window,
 2648        cx: &mut Context<Workspace>,
 2649    ) {
 2650        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2651    }
 2652
 2653    fn new_file_in_direction(
 2654        workspace: &mut Workspace,
 2655        direction: SplitDirection,
 2656        window: &mut Window,
 2657        cx: &mut Context<Workspace>,
 2658    ) {
 2659        let project = workspace.project().clone();
 2660        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2661
 2662        cx.spawn_in(window, async move |workspace, cx| {
 2663            let buffer = create.await?;
 2664            workspace.update_in(cx, move |workspace, window, cx| {
 2665                workspace.split_item(
 2666                    direction,
 2667                    Box::new(
 2668                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2669                    ),
 2670                    window,
 2671                    cx,
 2672                )
 2673            })?;
 2674            anyhow::Ok(())
 2675        })
 2676        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2677            match e.error_code() {
 2678                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2679                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2680                e.error_tag("required").unwrap_or("the latest version")
 2681            )),
 2682                _ => None,
 2683            }
 2684        });
 2685    }
 2686
 2687    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2688        self.leader_id
 2689    }
 2690
 2691    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2692        &self.buffer
 2693    }
 2694
 2695    pub fn project(&self) -> Option<&Entity<Project>> {
 2696        self.project.as_ref()
 2697    }
 2698
 2699    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2700        self.workspace.as_ref()?.0.upgrade()
 2701    }
 2702
 2703    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2704        self.buffer().read(cx).title(cx)
 2705    }
 2706
 2707    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2708        let git_blame_gutter_max_author_length = self
 2709            .render_git_blame_gutter(cx)
 2710            .then(|| {
 2711                if let Some(blame) = self.blame.as_ref() {
 2712                    let max_author_length =
 2713                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2714                    Some(max_author_length)
 2715                } else {
 2716                    None
 2717                }
 2718            })
 2719            .flatten();
 2720
 2721        EditorSnapshot {
 2722            mode: self.mode.clone(),
 2723            show_gutter: self.show_gutter,
 2724            show_line_numbers: self.show_line_numbers,
 2725            show_git_diff_gutter: self.show_git_diff_gutter,
 2726            show_code_actions: self.show_code_actions,
 2727            show_runnables: self.show_runnables,
 2728            show_breakpoints: self.show_breakpoints,
 2729            git_blame_gutter_max_author_length,
 2730            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2731            placeholder_display_snapshot: self
 2732                .placeholder_display_map
 2733                .as_ref()
 2734                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2735            scroll_anchor: self.scroll_manager.anchor(),
 2736            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2737            is_focused: self.focus_handle.is_focused(window),
 2738            current_line_highlight: self
 2739                .current_line_highlight
 2740                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2741            gutter_hovered: self.gutter_hovered,
 2742        }
 2743    }
 2744
 2745    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2746        self.buffer.read(cx).language_at(point, cx)
 2747    }
 2748
 2749    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2750        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2751    }
 2752
 2753    pub fn active_excerpt(
 2754        &self,
 2755        cx: &App,
 2756    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2757        self.buffer
 2758            .read(cx)
 2759            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2760    }
 2761
 2762    pub fn mode(&self) -> &EditorMode {
 2763        &self.mode
 2764    }
 2765
 2766    pub fn set_mode(&mut self, mode: EditorMode) {
 2767        self.mode = mode;
 2768    }
 2769
 2770    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2771        self.collaboration_hub.as_deref()
 2772    }
 2773
 2774    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2775        self.collaboration_hub = Some(hub);
 2776    }
 2777
 2778    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2779        self.in_project_search = in_project_search;
 2780    }
 2781
 2782    pub fn set_custom_context_menu(
 2783        &mut self,
 2784        f: impl 'static
 2785        + Fn(
 2786            &mut Self,
 2787            DisplayPoint,
 2788            &mut Window,
 2789            &mut Context<Self>,
 2790        ) -> Option<Entity<ui::ContextMenu>>,
 2791    ) {
 2792        self.custom_context_menu = Some(Box::new(f))
 2793    }
 2794
 2795    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2796        self.completion_provider = provider;
 2797    }
 2798
 2799    #[cfg(any(test, feature = "test-support"))]
 2800    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2801        self.completion_provider.clone()
 2802    }
 2803
 2804    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2805        self.semantics_provider.clone()
 2806    }
 2807
 2808    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2809        self.semantics_provider = provider;
 2810    }
 2811
 2812    pub fn set_edit_prediction_provider<T>(
 2813        &mut self,
 2814        provider: Option<Entity<T>>,
 2815        window: &mut Window,
 2816        cx: &mut Context<Self>,
 2817    ) where
 2818        T: EditPredictionProvider,
 2819    {
 2820        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2821            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2822                if this.focus_handle.is_focused(window) {
 2823                    this.update_visible_edit_prediction(window, cx);
 2824                }
 2825            }),
 2826            provider: Arc::new(provider),
 2827        });
 2828        self.update_edit_prediction_settings(cx);
 2829        self.refresh_edit_prediction(false, false, window, cx);
 2830    }
 2831
 2832    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2833        self.placeholder_display_map
 2834            .as_ref()
 2835            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2836    }
 2837
 2838    pub fn set_placeholder_text(
 2839        &mut self,
 2840        placeholder_text: &str,
 2841        window: &mut Window,
 2842        cx: &mut Context<Self>,
 2843    ) {
 2844        let multibuffer = cx
 2845            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2846
 2847        let style = window.text_style();
 2848
 2849        self.placeholder_display_map = Some(cx.new(|cx| {
 2850            DisplayMap::new(
 2851                multibuffer,
 2852                style.font(),
 2853                style.font_size.to_pixels(window.rem_size()),
 2854                None,
 2855                FILE_HEADER_HEIGHT,
 2856                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2857                Default::default(),
 2858                DiagnosticSeverity::Off,
 2859                cx,
 2860            )
 2861        }));
 2862        cx.notify();
 2863    }
 2864
 2865    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2866        self.cursor_shape = cursor_shape;
 2867
 2868        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2869        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2870
 2871        cx.notify();
 2872    }
 2873
 2874    pub fn set_current_line_highlight(
 2875        &mut self,
 2876        current_line_highlight: Option<CurrentLineHighlight>,
 2877    ) {
 2878        self.current_line_highlight = current_line_highlight;
 2879    }
 2880
 2881    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2882        self.collapse_matches = collapse_matches;
 2883    }
 2884
 2885    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2886        let buffers = self.buffer.read(cx).all_buffers();
 2887        let Some(project) = self.project.as_ref() else {
 2888            return;
 2889        };
 2890        project.update(cx, |project, cx| {
 2891            for buffer in buffers {
 2892                self.registered_buffers
 2893                    .entry(buffer.read(cx).remote_id())
 2894                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2895            }
 2896        })
 2897    }
 2898
 2899    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2900        if self.collapse_matches {
 2901            return range.start..range.start;
 2902        }
 2903        range.clone()
 2904    }
 2905
 2906    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2907        if self.display_map.read(cx).clip_at_line_ends != clip {
 2908            self.display_map
 2909                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2910        }
 2911    }
 2912
 2913    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2914        self.input_enabled = input_enabled;
 2915    }
 2916
 2917    pub fn set_edit_predictions_hidden_for_vim_mode(
 2918        &mut self,
 2919        hidden: bool,
 2920        window: &mut Window,
 2921        cx: &mut Context<Self>,
 2922    ) {
 2923        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2924            self.edit_predictions_hidden_for_vim_mode = hidden;
 2925            if hidden {
 2926                self.update_visible_edit_prediction(window, cx);
 2927            } else {
 2928                self.refresh_edit_prediction(true, false, window, cx);
 2929            }
 2930        }
 2931    }
 2932
 2933    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2934        self.menu_edit_predictions_policy = value;
 2935    }
 2936
 2937    pub fn set_autoindent(&mut self, autoindent: bool) {
 2938        if autoindent {
 2939            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2940        } else {
 2941            self.autoindent_mode = None;
 2942        }
 2943    }
 2944
 2945    pub fn read_only(&self, cx: &App) -> bool {
 2946        self.read_only || self.buffer.read(cx).read_only()
 2947    }
 2948
 2949    pub fn set_read_only(&mut self, read_only: bool) {
 2950        self.read_only = read_only;
 2951    }
 2952
 2953    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2954        self.use_autoclose = autoclose;
 2955    }
 2956
 2957    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2958        self.use_auto_surround = auto_surround;
 2959    }
 2960
 2961    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2962        self.auto_replace_emoji_shortcode = auto_replace;
 2963    }
 2964
 2965    pub fn toggle_edit_predictions(
 2966        &mut self,
 2967        _: &ToggleEditPrediction,
 2968        window: &mut Window,
 2969        cx: &mut Context<Self>,
 2970    ) {
 2971        if self.show_edit_predictions_override.is_some() {
 2972            self.set_show_edit_predictions(None, window, cx);
 2973        } else {
 2974            let show_edit_predictions = !self.edit_predictions_enabled();
 2975            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2976        }
 2977    }
 2978
 2979    pub fn set_show_edit_predictions(
 2980        &mut self,
 2981        show_edit_predictions: Option<bool>,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984    ) {
 2985        self.show_edit_predictions_override = show_edit_predictions;
 2986        self.update_edit_prediction_settings(cx);
 2987
 2988        if let Some(false) = show_edit_predictions {
 2989            self.discard_edit_prediction(false, cx);
 2990        } else {
 2991            self.refresh_edit_prediction(false, true, window, cx);
 2992        }
 2993    }
 2994
 2995    fn edit_predictions_disabled_in_scope(
 2996        &self,
 2997        buffer: &Entity<Buffer>,
 2998        buffer_position: language::Anchor,
 2999        cx: &App,
 3000    ) -> bool {
 3001        let snapshot = buffer.read(cx).snapshot();
 3002        let settings = snapshot.settings_at(buffer_position, cx);
 3003
 3004        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3005            return false;
 3006        };
 3007
 3008        scope.override_name().is_some_and(|scope_name| {
 3009            settings
 3010                .edit_predictions_disabled_in
 3011                .iter()
 3012                .any(|s| s == scope_name)
 3013        })
 3014    }
 3015
 3016    pub fn set_use_modal_editing(&mut self, to: bool) {
 3017        self.use_modal_editing = to;
 3018    }
 3019
 3020    pub fn use_modal_editing(&self) -> bool {
 3021        self.use_modal_editing
 3022    }
 3023
 3024    fn selections_did_change(
 3025        &mut self,
 3026        local: bool,
 3027        old_cursor_position: &Anchor,
 3028        effects: SelectionEffects,
 3029        window: &mut Window,
 3030        cx: &mut Context<Self>,
 3031    ) {
 3032        window.invalidate_character_coordinates();
 3033
 3034        // Copy selections to primary selection buffer
 3035        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3036        if local {
 3037            let selections = self.selections.all::<usize>(cx);
 3038            let buffer_handle = self.buffer.read(cx).read(cx);
 3039
 3040            let mut text = String::new();
 3041            for (index, selection) in selections.iter().enumerate() {
 3042                let text_for_selection = buffer_handle
 3043                    .text_for_range(selection.start..selection.end)
 3044                    .collect::<String>();
 3045
 3046                text.push_str(&text_for_selection);
 3047                if index != selections.len() - 1 {
 3048                    text.push('\n');
 3049                }
 3050            }
 3051
 3052            if !text.is_empty() {
 3053                cx.write_to_primary(ClipboardItem::new_string(text));
 3054            }
 3055        }
 3056
 3057        let selection_anchors = self.selections.disjoint_anchors();
 3058
 3059        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3060            self.buffer.update(cx, |buffer, cx| {
 3061                buffer.set_active_selections(
 3062                    &selection_anchors,
 3063                    self.selections.line_mode,
 3064                    self.cursor_shape,
 3065                    cx,
 3066                )
 3067            });
 3068        }
 3069        let display_map = self
 3070            .display_map
 3071            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3072        let buffer = &display_map.buffer_snapshot;
 3073        if self.selections.count() == 1 {
 3074            self.add_selections_state = None;
 3075        }
 3076        self.select_next_state = None;
 3077        self.select_prev_state = None;
 3078        self.select_syntax_node_history.try_clear();
 3079        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3080        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3081        self.take_rename(false, window, cx);
 3082
 3083        let newest_selection = self.selections.newest_anchor();
 3084        let new_cursor_position = newest_selection.head();
 3085        let selection_start = newest_selection.start;
 3086
 3087        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3088            self.push_to_nav_history(
 3089                *old_cursor_position,
 3090                Some(new_cursor_position.to_point(buffer)),
 3091                false,
 3092                effects.nav_history == Some(true),
 3093                cx,
 3094            );
 3095        }
 3096
 3097        if local {
 3098            if let Some(buffer_id) = new_cursor_position.buffer_id
 3099                && !self.registered_buffers.contains_key(&buffer_id)
 3100                && let Some(project) = self.project.as_ref()
 3101            {
 3102                project.update(cx, |project, cx| {
 3103                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3104                        return;
 3105                    };
 3106                    self.registered_buffers.insert(
 3107                        buffer_id,
 3108                        project.register_buffer_with_language_servers(&buffer, cx),
 3109                    );
 3110                })
 3111            }
 3112
 3113            let mut context_menu = self.context_menu.borrow_mut();
 3114            let completion_menu = match context_menu.as_ref() {
 3115                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3116                Some(CodeContextMenu::CodeActions(_)) => {
 3117                    *context_menu = None;
 3118                    None
 3119                }
 3120                None => None,
 3121            };
 3122            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3123            drop(context_menu);
 3124
 3125            if effects.completions
 3126                && let Some(completion_position) = completion_position
 3127            {
 3128                let start_offset = selection_start.to_offset(buffer);
 3129                let position_matches = start_offset == completion_position.to_offset(buffer);
 3130                let continue_showing = if position_matches {
 3131                    if self.snippet_stack.is_empty() {
 3132                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3133                    } else {
 3134                        // Snippet choices can be shown even when the cursor is in whitespace.
 3135                        // Dismissing the menu with actions like backspace is handled by
 3136                        // invalidation regions.
 3137                        true
 3138                    }
 3139                } else {
 3140                    false
 3141                };
 3142
 3143                if continue_showing {
 3144                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3145                } else {
 3146                    self.hide_context_menu(window, cx);
 3147                }
 3148            }
 3149
 3150            hide_hover(self, cx);
 3151
 3152            if old_cursor_position.to_display_point(&display_map).row()
 3153                != new_cursor_position.to_display_point(&display_map).row()
 3154            {
 3155                self.available_code_actions.take();
 3156            }
 3157            self.refresh_code_actions(window, cx);
 3158            self.refresh_document_highlights(cx);
 3159            self.refresh_selected_text_highlights(false, window, cx);
 3160            refresh_matching_bracket_highlights(self, window, cx);
 3161            self.update_visible_edit_prediction(window, cx);
 3162            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3163            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3164            self.inline_blame_popover.take();
 3165            if self.git_blame_inline_enabled {
 3166                self.start_inline_blame_timer(window, cx);
 3167            }
 3168        }
 3169
 3170        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3171        cx.emit(EditorEvent::SelectionsChanged { local });
 3172
 3173        let selections = &self.selections.disjoint;
 3174        if selections.len() == 1 {
 3175            cx.emit(SearchEvent::ActiveMatchChanged)
 3176        }
 3177        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3178            let inmemory_selections = selections
 3179                .iter()
 3180                .map(|s| {
 3181                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3182                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3183                })
 3184                .collect();
 3185            self.update_restoration_data(cx, |data| {
 3186                data.selections = inmemory_selections;
 3187            });
 3188
 3189            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3190                && let Some(workspace_id) =
 3191                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3192            {
 3193                let snapshot = self.buffer().read(cx).snapshot(cx);
 3194                let selections = selections.clone();
 3195                let background_executor = cx.background_executor().clone();
 3196                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3197                self.serialize_selections = cx.background_spawn(async move {
 3198                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3199                            let db_selections = selections
 3200                                .iter()
 3201                                .map(|selection| {
 3202                                    (
 3203                                        selection.start.to_offset(&snapshot),
 3204                                        selection.end.to_offset(&snapshot),
 3205                                    )
 3206                                })
 3207                                .collect();
 3208
 3209                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3210                                .await
 3211                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3212                                .log_err();
 3213                        });
 3214            }
 3215        }
 3216
 3217        cx.notify();
 3218    }
 3219
 3220    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3221        use text::ToOffset as _;
 3222        use text::ToPoint as _;
 3223
 3224        if self.mode.is_minimap()
 3225            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3226        {
 3227            return;
 3228        }
 3229
 3230        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3231            return;
 3232        };
 3233
 3234        let snapshot = singleton.read(cx).snapshot();
 3235        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3236            let display_snapshot = display_map.snapshot(cx);
 3237
 3238            display_snapshot
 3239                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3240                .map(|fold| {
 3241                    fold.range.start.text_anchor.to_point(&snapshot)
 3242                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3243                })
 3244                .collect()
 3245        });
 3246        self.update_restoration_data(cx, |data| {
 3247            data.folds = inmemory_folds;
 3248        });
 3249
 3250        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3251            return;
 3252        };
 3253        let background_executor = cx.background_executor().clone();
 3254        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3255        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3256            display_map
 3257                .snapshot(cx)
 3258                .folds_in_range(0..snapshot.len())
 3259                .map(|fold| {
 3260                    (
 3261                        fold.range.start.text_anchor.to_offset(&snapshot),
 3262                        fold.range.end.text_anchor.to_offset(&snapshot),
 3263                    )
 3264                })
 3265                .collect()
 3266        });
 3267        self.serialize_folds = cx.background_spawn(async move {
 3268            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3269            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3270                .await
 3271                .with_context(|| {
 3272                    format!(
 3273                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3274                    )
 3275                })
 3276                .log_err();
 3277        });
 3278    }
 3279
 3280    pub fn sync_selections(
 3281        &mut self,
 3282        other: Entity<Editor>,
 3283        cx: &mut Context<Self>,
 3284    ) -> gpui::Subscription {
 3285        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3286        self.selections.change_with(cx, |selections| {
 3287            selections.select_anchors(other_selections);
 3288        });
 3289
 3290        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3291            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3292                let other_selections = other.read(cx).selections.disjoint.to_vec();
 3293                if other_selections.is_empty() {
 3294                    return;
 3295                }
 3296                this.selections.change_with(cx, |selections| {
 3297                    selections.select_anchors(other_selections);
 3298                });
 3299            }
 3300        });
 3301
 3302        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3303            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3304                let these_selections = this.selections.disjoint.to_vec();
 3305                if these_selections.is_empty() {
 3306                    return;
 3307                }
 3308                other.update(cx, |other_editor, cx| {
 3309                    other_editor.selections.change_with(cx, |selections| {
 3310                        selections.select_anchors(these_selections);
 3311                    })
 3312                });
 3313            }
 3314        });
 3315
 3316        Subscription::join(other_subscription, this_subscription)
 3317    }
 3318
 3319    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3320    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3321    /// effects of selection change occur at the end of the transaction.
 3322    pub fn change_selections<R>(
 3323        &mut self,
 3324        effects: SelectionEffects,
 3325        window: &mut Window,
 3326        cx: &mut Context<Self>,
 3327        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3328    ) -> R {
 3329        if let Some(state) = &mut self.deferred_selection_effects_state {
 3330            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3331            state.effects.completions = effects.completions;
 3332            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3333            let (changed, result) = self.selections.change_with(cx, change);
 3334            state.changed |= changed;
 3335            return result;
 3336        }
 3337        let mut state = DeferredSelectionEffectsState {
 3338            changed: false,
 3339            effects,
 3340            old_cursor_position: self.selections.newest_anchor().head(),
 3341            history_entry: SelectionHistoryEntry {
 3342                selections: self.selections.disjoint_anchors(),
 3343                select_next_state: self.select_next_state.clone(),
 3344                select_prev_state: self.select_prev_state.clone(),
 3345                add_selections_state: self.add_selections_state.clone(),
 3346            },
 3347        };
 3348        let (changed, result) = self.selections.change_with(cx, change);
 3349        state.changed = state.changed || changed;
 3350        if self.defer_selection_effects {
 3351            self.deferred_selection_effects_state = Some(state);
 3352        } else {
 3353            self.apply_selection_effects(state, window, cx);
 3354        }
 3355        result
 3356    }
 3357
 3358    /// Defers the effects of selection change, so that the effects of multiple calls to
 3359    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3360    /// to selection history and the state of popovers based on selection position aren't
 3361    /// erroneously updated.
 3362    pub fn with_selection_effects_deferred<R>(
 3363        &mut self,
 3364        window: &mut Window,
 3365        cx: &mut Context<Self>,
 3366        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3367    ) -> R {
 3368        let already_deferred = self.defer_selection_effects;
 3369        self.defer_selection_effects = true;
 3370        let result = update(self, window, cx);
 3371        if !already_deferred {
 3372            self.defer_selection_effects = false;
 3373            if let Some(state) = self.deferred_selection_effects_state.take() {
 3374                self.apply_selection_effects(state, window, cx);
 3375            }
 3376        }
 3377        result
 3378    }
 3379
 3380    fn apply_selection_effects(
 3381        &mut self,
 3382        state: DeferredSelectionEffectsState,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385    ) {
 3386        if state.changed {
 3387            self.selection_history.push(state.history_entry);
 3388
 3389            if let Some(autoscroll) = state.effects.scroll {
 3390                self.request_autoscroll(autoscroll, cx);
 3391            }
 3392
 3393            let old_cursor_position = &state.old_cursor_position;
 3394
 3395            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3396
 3397            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3398                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3399            }
 3400        }
 3401    }
 3402
 3403    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3404    where
 3405        I: IntoIterator<Item = (Range<S>, T)>,
 3406        S: ToOffset,
 3407        T: Into<Arc<str>>,
 3408    {
 3409        if self.read_only(cx) {
 3410            return;
 3411        }
 3412
 3413        self.buffer
 3414            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3415    }
 3416
 3417    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3418    where
 3419        I: IntoIterator<Item = (Range<S>, T)>,
 3420        S: ToOffset,
 3421        T: Into<Arc<str>>,
 3422    {
 3423        if self.read_only(cx) {
 3424            return;
 3425        }
 3426
 3427        self.buffer.update(cx, |buffer, cx| {
 3428            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3429        });
 3430    }
 3431
 3432    pub fn edit_with_block_indent<I, S, T>(
 3433        &mut self,
 3434        edits: I,
 3435        original_indent_columns: Vec<Option<u32>>,
 3436        cx: &mut Context<Self>,
 3437    ) where
 3438        I: IntoIterator<Item = (Range<S>, T)>,
 3439        S: ToOffset,
 3440        T: Into<Arc<str>>,
 3441    {
 3442        if self.read_only(cx) {
 3443            return;
 3444        }
 3445
 3446        self.buffer.update(cx, |buffer, cx| {
 3447            buffer.edit(
 3448                edits,
 3449                Some(AutoindentMode::Block {
 3450                    original_indent_columns,
 3451                }),
 3452                cx,
 3453            )
 3454        });
 3455    }
 3456
 3457    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3458        self.hide_context_menu(window, cx);
 3459
 3460        match phase {
 3461            SelectPhase::Begin {
 3462                position,
 3463                add,
 3464                click_count,
 3465            } => self.begin_selection(position, add, click_count, window, cx),
 3466            SelectPhase::BeginColumnar {
 3467                position,
 3468                goal_column,
 3469                reset,
 3470                mode,
 3471            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3472            SelectPhase::Extend {
 3473                position,
 3474                click_count,
 3475            } => self.extend_selection(position, click_count, window, cx),
 3476            SelectPhase::Update {
 3477                position,
 3478                goal_column,
 3479                scroll_delta,
 3480            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3481            SelectPhase::End => self.end_selection(window, cx),
 3482        }
 3483    }
 3484
 3485    fn extend_selection(
 3486        &mut self,
 3487        position: DisplayPoint,
 3488        click_count: usize,
 3489        window: &mut Window,
 3490        cx: &mut Context<Self>,
 3491    ) {
 3492        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3493        let tail = self.selections.newest::<usize>(cx).tail();
 3494        self.begin_selection(position, false, click_count, window, cx);
 3495
 3496        let position = position.to_offset(&display_map, Bias::Left);
 3497        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3498
 3499        let mut pending_selection = self
 3500            .selections
 3501            .pending_anchor()
 3502            .expect("extend_selection not called with pending selection");
 3503        if position >= tail {
 3504            pending_selection.start = tail_anchor;
 3505        } else {
 3506            pending_selection.end = tail_anchor;
 3507            pending_selection.reversed = true;
 3508        }
 3509
 3510        let mut pending_mode = self.selections.pending_mode().unwrap();
 3511        match &mut pending_mode {
 3512            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3513            _ => {}
 3514        }
 3515
 3516        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3517            SelectionEffects::scroll(Autoscroll::fit())
 3518        } else {
 3519            SelectionEffects::no_scroll()
 3520        };
 3521
 3522        self.change_selections(effects, window, cx, |s| {
 3523            s.set_pending(pending_selection, pending_mode)
 3524        });
 3525    }
 3526
 3527    fn begin_selection(
 3528        &mut self,
 3529        position: DisplayPoint,
 3530        add: bool,
 3531        click_count: usize,
 3532        window: &mut Window,
 3533        cx: &mut Context<Self>,
 3534    ) {
 3535        if !self.focus_handle.is_focused(window) {
 3536            self.last_focused_descendant = None;
 3537            window.focus(&self.focus_handle);
 3538        }
 3539
 3540        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3541        let buffer = &display_map.buffer_snapshot;
 3542        let position = display_map.clip_point(position, Bias::Left);
 3543
 3544        let start;
 3545        let end;
 3546        let mode;
 3547        let mut auto_scroll;
 3548        match click_count {
 3549            1 => {
 3550                start = buffer.anchor_before(position.to_point(&display_map));
 3551                end = start;
 3552                mode = SelectMode::Character;
 3553                auto_scroll = true;
 3554            }
 3555            2 => {
 3556                let position = display_map
 3557                    .clip_point(position, Bias::Left)
 3558                    .to_offset(&display_map, Bias::Left);
 3559                let (range, _) = buffer.surrounding_word(position, false);
 3560                start = buffer.anchor_before(range.start);
 3561                end = buffer.anchor_before(range.end);
 3562                mode = SelectMode::Word(start..end);
 3563                auto_scroll = true;
 3564            }
 3565            3 => {
 3566                let position = display_map
 3567                    .clip_point(position, Bias::Left)
 3568                    .to_point(&display_map);
 3569                let line_start = display_map.prev_line_boundary(position).0;
 3570                let next_line_start = buffer.clip_point(
 3571                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3572                    Bias::Left,
 3573                );
 3574                start = buffer.anchor_before(line_start);
 3575                end = buffer.anchor_before(next_line_start);
 3576                mode = SelectMode::Line(start..end);
 3577                auto_scroll = true;
 3578            }
 3579            _ => {
 3580                start = buffer.anchor_before(0);
 3581                end = buffer.anchor_before(buffer.len());
 3582                mode = SelectMode::All;
 3583                auto_scroll = false;
 3584            }
 3585        }
 3586        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3587
 3588        let point_to_delete: Option<usize> = {
 3589            let selected_points: Vec<Selection<Point>> =
 3590                self.selections.disjoint_in_range(start..end, cx);
 3591
 3592            if !add || click_count > 1 {
 3593                None
 3594            } else if !selected_points.is_empty() {
 3595                Some(selected_points[0].id)
 3596            } else {
 3597                let clicked_point_already_selected =
 3598                    self.selections.disjoint.iter().find(|selection| {
 3599                        selection.start.to_point(buffer) == start.to_point(buffer)
 3600                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3601                    });
 3602
 3603                clicked_point_already_selected.map(|selection| selection.id)
 3604            }
 3605        };
 3606
 3607        let selections_count = self.selections.count();
 3608        let effects = if auto_scroll {
 3609            SelectionEffects::default()
 3610        } else {
 3611            SelectionEffects::no_scroll()
 3612        };
 3613
 3614        self.change_selections(effects, window, cx, |s| {
 3615            if let Some(point_to_delete) = point_to_delete {
 3616                s.delete(point_to_delete);
 3617
 3618                if selections_count == 1 {
 3619                    s.set_pending_anchor_range(start..end, mode);
 3620                }
 3621            } else {
 3622                if !add {
 3623                    s.clear_disjoint();
 3624                }
 3625
 3626                s.set_pending_anchor_range(start..end, mode);
 3627            }
 3628        });
 3629    }
 3630
 3631    fn begin_columnar_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        reset: bool,
 3636        mode: ColumnarMode,
 3637        window: &mut Window,
 3638        cx: &mut Context<Self>,
 3639    ) {
 3640        if !self.focus_handle.is_focused(window) {
 3641            self.last_focused_descendant = None;
 3642            window.focus(&self.focus_handle);
 3643        }
 3644
 3645        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3646
 3647        if reset {
 3648            let pointer_position = display_map
 3649                .buffer_snapshot
 3650                .anchor_before(position.to_point(&display_map));
 3651
 3652            self.change_selections(
 3653                SelectionEffects::scroll(Autoscroll::newest()),
 3654                window,
 3655                cx,
 3656                |s| {
 3657                    s.clear_disjoint();
 3658                    s.set_pending_anchor_range(
 3659                        pointer_position..pointer_position,
 3660                        SelectMode::Character,
 3661                    );
 3662                },
 3663            );
 3664        };
 3665
 3666        let tail = self.selections.newest::<Point>(cx).tail();
 3667        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3668        self.columnar_selection_state = match mode {
 3669            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3670                selection_tail: selection_anchor,
 3671                display_point: if reset {
 3672                    if position.column() != goal_column {
 3673                        Some(DisplayPoint::new(position.row(), goal_column))
 3674                    } else {
 3675                        None
 3676                    }
 3677                } else {
 3678                    None
 3679                },
 3680            }),
 3681            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3682                selection_tail: selection_anchor,
 3683            }),
 3684        };
 3685
 3686        if !reset {
 3687            self.select_columns(position, goal_column, &display_map, window, cx);
 3688        }
 3689    }
 3690
 3691    fn update_selection(
 3692        &mut self,
 3693        position: DisplayPoint,
 3694        goal_column: u32,
 3695        scroll_delta: gpui::Point<f32>,
 3696        window: &mut Window,
 3697        cx: &mut Context<Self>,
 3698    ) {
 3699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3700
 3701        if self.columnar_selection_state.is_some() {
 3702            self.select_columns(position, goal_column, &display_map, window, cx);
 3703        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3704            let buffer = &display_map.buffer_snapshot;
 3705            let head;
 3706            let tail;
 3707            let mode = self.selections.pending_mode().unwrap();
 3708            match &mode {
 3709                SelectMode::Character => {
 3710                    head = position.to_point(&display_map);
 3711                    tail = pending.tail().to_point(buffer);
 3712                }
 3713                SelectMode::Word(original_range) => {
 3714                    let offset = display_map
 3715                        .clip_point(position, Bias::Left)
 3716                        .to_offset(&display_map, Bias::Left);
 3717                    let original_range = original_range.to_offset(buffer);
 3718
 3719                    let head_offset = if buffer.is_inside_word(offset, false)
 3720                        || original_range.contains(&offset)
 3721                    {
 3722                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3723                        if word_range.start < original_range.start {
 3724                            word_range.start
 3725                        } else {
 3726                            word_range.end
 3727                        }
 3728                    } else {
 3729                        offset
 3730                    };
 3731
 3732                    head = head_offset.to_point(buffer);
 3733                    if head_offset <= original_range.start {
 3734                        tail = original_range.end.to_point(buffer);
 3735                    } else {
 3736                        tail = original_range.start.to_point(buffer);
 3737                    }
 3738                }
 3739                SelectMode::Line(original_range) => {
 3740                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3741
 3742                    let position = display_map
 3743                        .clip_point(position, Bias::Left)
 3744                        .to_point(&display_map);
 3745                    let line_start = display_map.prev_line_boundary(position).0;
 3746                    let next_line_start = buffer.clip_point(
 3747                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3748                        Bias::Left,
 3749                    );
 3750
 3751                    if line_start < original_range.start {
 3752                        head = line_start
 3753                    } else {
 3754                        head = next_line_start
 3755                    }
 3756
 3757                    if head <= original_range.start {
 3758                        tail = original_range.end;
 3759                    } else {
 3760                        tail = original_range.start;
 3761                    }
 3762                }
 3763                SelectMode::All => {
 3764                    return;
 3765                }
 3766            };
 3767
 3768            if head < tail {
 3769                pending.start = buffer.anchor_before(head);
 3770                pending.end = buffer.anchor_before(tail);
 3771                pending.reversed = true;
 3772            } else {
 3773                pending.start = buffer.anchor_before(tail);
 3774                pending.end = buffer.anchor_before(head);
 3775                pending.reversed = false;
 3776            }
 3777
 3778            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3779                s.set_pending(pending, mode);
 3780            });
 3781        } else {
 3782            log::error!("update_selection dispatched with no pending selection");
 3783            return;
 3784        }
 3785
 3786        self.apply_scroll_delta(scroll_delta, window, cx);
 3787        cx.notify();
 3788    }
 3789
 3790    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3791        self.columnar_selection_state.take();
 3792        if self.selections.pending_anchor().is_some() {
 3793            let selections = self.selections.all::<usize>(cx);
 3794            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3795                s.select(selections);
 3796                s.clear_pending();
 3797            });
 3798        }
 3799    }
 3800
 3801    fn select_columns(
 3802        &mut self,
 3803        head: DisplayPoint,
 3804        goal_column: u32,
 3805        display_map: &DisplaySnapshot,
 3806        window: &mut Window,
 3807        cx: &mut Context<Self>,
 3808    ) {
 3809        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3810            return;
 3811        };
 3812
 3813        let tail = match columnar_state {
 3814            ColumnarSelectionState::FromMouse {
 3815                selection_tail,
 3816                display_point,
 3817            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3818            ColumnarSelectionState::FromSelection { selection_tail } => {
 3819                selection_tail.to_display_point(display_map)
 3820            }
 3821        };
 3822
 3823        let start_row = cmp::min(tail.row(), head.row());
 3824        let end_row = cmp::max(tail.row(), head.row());
 3825        let start_column = cmp::min(tail.column(), goal_column);
 3826        let end_column = cmp::max(tail.column(), goal_column);
 3827        let reversed = start_column < tail.column();
 3828
 3829        let selection_ranges = (start_row.0..=end_row.0)
 3830            .map(DisplayRow)
 3831            .filter_map(|row| {
 3832                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3833                    || start_column <= display_map.line_len(row))
 3834                    && !display_map.is_block_line(row)
 3835                {
 3836                    let start = display_map
 3837                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3838                        .to_point(display_map);
 3839                    let end = display_map
 3840                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3841                        .to_point(display_map);
 3842                    if reversed {
 3843                        Some(end..start)
 3844                    } else {
 3845                        Some(start..end)
 3846                    }
 3847                } else {
 3848                    None
 3849                }
 3850            })
 3851            .collect::<Vec<_>>();
 3852
 3853        let ranges = match columnar_state {
 3854            ColumnarSelectionState::FromMouse { .. } => {
 3855                let mut non_empty_ranges = selection_ranges
 3856                    .iter()
 3857                    .filter(|selection_range| selection_range.start != selection_range.end)
 3858                    .peekable();
 3859                if non_empty_ranges.peek().is_some() {
 3860                    non_empty_ranges.cloned().collect()
 3861                } else {
 3862                    selection_ranges
 3863                }
 3864            }
 3865            _ => selection_ranges,
 3866        };
 3867
 3868        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3869            s.select_ranges(ranges);
 3870        });
 3871        cx.notify();
 3872    }
 3873
 3874    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3875        self.selections
 3876            .all_adjusted(cx)
 3877            .iter()
 3878            .any(|selection| !selection.is_empty())
 3879    }
 3880
 3881    pub fn has_pending_nonempty_selection(&self) -> bool {
 3882        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3883            Some(Selection { start, end, .. }) => start != end,
 3884            None => false,
 3885        };
 3886
 3887        pending_nonempty_selection
 3888            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3889    }
 3890
 3891    pub fn has_pending_selection(&self) -> bool {
 3892        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3893    }
 3894
 3895    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3896        self.selection_mark_mode = false;
 3897        self.selection_drag_state = SelectionDragState::None;
 3898
 3899        if self.clear_expanded_diff_hunks(cx) {
 3900            cx.notify();
 3901            return;
 3902        }
 3903        if self.dismiss_menus_and_popups(true, window, cx) {
 3904            return;
 3905        }
 3906
 3907        if self.mode.is_full()
 3908            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3909        {
 3910            return;
 3911        }
 3912
 3913        cx.propagate();
 3914    }
 3915
 3916    pub fn dismiss_menus_and_popups(
 3917        &mut self,
 3918        is_user_requested: bool,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) -> bool {
 3922        if self.take_rename(false, window, cx).is_some() {
 3923            return true;
 3924        }
 3925
 3926        if hide_hover(self, cx) {
 3927            return true;
 3928        }
 3929
 3930        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3931            return true;
 3932        }
 3933
 3934        if self.hide_context_menu(window, cx).is_some() {
 3935            return true;
 3936        }
 3937
 3938        if self.mouse_context_menu.take().is_some() {
 3939            return true;
 3940        }
 3941
 3942        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3943            return true;
 3944        }
 3945
 3946        if self.snippet_stack.pop().is_some() {
 3947            return true;
 3948        }
 3949
 3950        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3951            self.dismiss_diagnostics(cx);
 3952            return true;
 3953        }
 3954
 3955        false
 3956    }
 3957
 3958    fn linked_editing_ranges_for(
 3959        &self,
 3960        selection: Range<text::Anchor>,
 3961        cx: &App,
 3962    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3963        if self.linked_edit_ranges.is_empty() {
 3964            return None;
 3965        }
 3966        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3967            selection.end.buffer_id.and_then(|end_buffer_id| {
 3968                if selection.start.buffer_id != Some(end_buffer_id) {
 3969                    return None;
 3970                }
 3971                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3972                let snapshot = buffer.read(cx).snapshot();
 3973                self.linked_edit_ranges
 3974                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3975                    .map(|ranges| (ranges, snapshot, buffer))
 3976            })?;
 3977        use text::ToOffset as TO;
 3978        // find offset from the start of current range to current cursor position
 3979        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3980
 3981        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3982        let start_difference = start_offset - start_byte_offset;
 3983        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3984        let end_difference = end_offset - start_byte_offset;
 3985        // Current range has associated linked ranges.
 3986        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3987        for range in linked_ranges.iter() {
 3988            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3989            let end_offset = start_offset + end_difference;
 3990            let start_offset = start_offset + start_difference;
 3991            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3992                continue;
 3993            }
 3994            if self.selections.disjoint_anchor_ranges().any(|s| {
 3995                if s.start.buffer_id != selection.start.buffer_id
 3996                    || s.end.buffer_id != selection.end.buffer_id
 3997                {
 3998                    return false;
 3999                }
 4000                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4001                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4002            }) {
 4003                continue;
 4004            }
 4005            let start = buffer_snapshot.anchor_after(start_offset);
 4006            let end = buffer_snapshot.anchor_after(end_offset);
 4007            linked_edits
 4008                .entry(buffer.clone())
 4009                .or_default()
 4010                .push(start..end);
 4011        }
 4012        Some(linked_edits)
 4013    }
 4014
 4015    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4016        let text: Arc<str> = text.into();
 4017
 4018        if self.read_only(cx) {
 4019            return;
 4020        }
 4021
 4022        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4023
 4024        let selections = self.selections.all_adjusted(cx);
 4025        let mut bracket_inserted = false;
 4026        let mut edits = Vec::new();
 4027        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4028        let mut new_selections = Vec::with_capacity(selections.len());
 4029        let mut new_autoclose_regions = Vec::new();
 4030        let snapshot = self.buffer.read(cx).read(cx);
 4031        let mut clear_linked_edit_ranges = false;
 4032
 4033        for (selection, autoclose_region) in
 4034            self.selections_with_autoclose_regions(selections, &snapshot)
 4035        {
 4036            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4037                // Determine if the inserted text matches the opening or closing
 4038                // bracket of any of this language's bracket pairs.
 4039                let mut bracket_pair = None;
 4040                let mut is_bracket_pair_start = false;
 4041                let mut is_bracket_pair_end = false;
 4042                if !text.is_empty() {
 4043                    let mut bracket_pair_matching_end = None;
 4044                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4045                    //  and they are removing the character that triggered IME popup.
 4046                    for (pair, enabled) in scope.brackets() {
 4047                        if !pair.close && !pair.surround {
 4048                            continue;
 4049                        }
 4050
 4051                        if enabled && pair.start.ends_with(text.as_ref()) {
 4052                            let prefix_len = pair.start.len() - text.len();
 4053                            let preceding_text_matches_prefix = prefix_len == 0
 4054                                || (selection.start.column >= (prefix_len as u32)
 4055                                    && snapshot.contains_str_at(
 4056                                        Point::new(
 4057                                            selection.start.row,
 4058                                            selection.start.column - (prefix_len as u32),
 4059                                        ),
 4060                                        &pair.start[..prefix_len],
 4061                                    ));
 4062                            if preceding_text_matches_prefix {
 4063                                bracket_pair = Some(pair.clone());
 4064                                is_bracket_pair_start = true;
 4065                                break;
 4066                            }
 4067                        }
 4068                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4069                        {
 4070                            // take first bracket pair matching end, but don't break in case a later bracket
 4071                            // pair matches start
 4072                            bracket_pair_matching_end = Some(pair.clone());
 4073                        }
 4074                    }
 4075                    if let Some(end) = bracket_pair_matching_end
 4076                        && bracket_pair.is_none()
 4077                    {
 4078                        bracket_pair = Some(end);
 4079                        is_bracket_pair_end = true;
 4080                    }
 4081                }
 4082
 4083                if let Some(bracket_pair) = bracket_pair {
 4084                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4085                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4086                    let auto_surround =
 4087                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4088                    if selection.is_empty() {
 4089                        if is_bracket_pair_start {
 4090                            // If the inserted text is a suffix of an opening bracket and the
 4091                            // selection is preceded by the rest of the opening bracket, then
 4092                            // insert the closing bracket.
 4093                            let following_text_allows_autoclose = snapshot
 4094                                .chars_at(selection.start)
 4095                                .next()
 4096                                .is_none_or(|c| scope.should_autoclose_before(c));
 4097
 4098                            let preceding_text_allows_autoclose = selection.start.column == 0
 4099                                || snapshot
 4100                                    .reversed_chars_at(selection.start)
 4101                                    .next()
 4102                                    .is_none_or(|c| {
 4103                                        bracket_pair.start != bracket_pair.end
 4104                                            || !snapshot
 4105                                                .char_classifier_at(selection.start)
 4106                                                .is_word(c)
 4107                                    });
 4108
 4109                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4110                                && bracket_pair.start.len() == 1
 4111                            {
 4112                                let target = bracket_pair.start.chars().next().unwrap();
 4113                                let current_line_count = snapshot
 4114                                    .reversed_chars_at(selection.start)
 4115                                    .take_while(|&c| c != '\n')
 4116                                    .filter(|&c| c == target)
 4117                                    .count();
 4118                                current_line_count % 2 == 1
 4119                            } else {
 4120                                false
 4121                            };
 4122
 4123                            if autoclose
 4124                                && bracket_pair.close
 4125                                && following_text_allows_autoclose
 4126                                && preceding_text_allows_autoclose
 4127                                && !is_closing_quote
 4128                            {
 4129                                let anchor = snapshot.anchor_before(selection.end);
 4130                                new_selections.push((selection.map(|_| anchor), text.len()));
 4131                                new_autoclose_regions.push((
 4132                                    anchor,
 4133                                    text.len(),
 4134                                    selection.id,
 4135                                    bracket_pair.clone(),
 4136                                ));
 4137                                edits.push((
 4138                                    selection.range(),
 4139                                    format!("{}{}", text, bracket_pair.end).into(),
 4140                                ));
 4141                                bracket_inserted = true;
 4142                                continue;
 4143                            }
 4144                        }
 4145
 4146                        if let Some(region) = autoclose_region {
 4147                            // If the selection is followed by an auto-inserted closing bracket,
 4148                            // then don't insert that closing bracket again; just move the selection
 4149                            // past the closing bracket.
 4150                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4151                                && text.as_ref() == region.pair.end.as_str()
 4152                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4153                            if should_skip {
 4154                                let anchor = snapshot.anchor_after(selection.end);
 4155                                new_selections
 4156                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4157                                continue;
 4158                            }
 4159                        }
 4160
 4161                        let always_treat_brackets_as_autoclosed = snapshot
 4162                            .language_settings_at(selection.start, cx)
 4163                            .always_treat_brackets_as_autoclosed;
 4164                        if always_treat_brackets_as_autoclosed
 4165                            && is_bracket_pair_end
 4166                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4167                        {
 4168                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4169                            // and the inserted text is a closing bracket and the selection is followed
 4170                            // by the closing bracket then move the selection past the closing bracket.
 4171                            let anchor = snapshot.anchor_after(selection.end);
 4172                            new_selections.push((selection.map(|_| anchor), text.len()));
 4173                            continue;
 4174                        }
 4175                    }
 4176                    // If an opening bracket is 1 character long and is typed while
 4177                    // text is selected, then surround that text with the bracket pair.
 4178                    else if auto_surround
 4179                        && bracket_pair.surround
 4180                        && is_bracket_pair_start
 4181                        && bracket_pair.start.chars().count() == 1
 4182                    {
 4183                        edits.push((selection.start..selection.start, text.clone()));
 4184                        edits.push((
 4185                            selection.end..selection.end,
 4186                            bracket_pair.end.as_str().into(),
 4187                        ));
 4188                        bracket_inserted = true;
 4189                        new_selections.push((
 4190                            Selection {
 4191                                id: selection.id,
 4192                                start: snapshot.anchor_after(selection.start),
 4193                                end: snapshot.anchor_before(selection.end),
 4194                                reversed: selection.reversed,
 4195                                goal: selection.goal,
 4196                            },
 4197                            0,
 4198                        ));
 4199                        continue;
 4200                    }
 4201                }
 4202            }
 4203
 4204            if self.auto_replace_emoji_shortcode
 4205                && selection.is_empty()
 4206                && text.as_ref().ends_with(':')
 4207                && let Some(possible_emoji_short_code) =
 4208                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4209                && !possible_emoji_short_code.is_empty()
 4210                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4211            {
 4212                let emoji_shortcode_start = Point::new(
 4213                    selection.start.row,
 4214                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4215                );
 4216
 4217                // Remove shortcode from buffer
 4218                edits.push((
 4219                    emoji_shortcode_start..selection.start,
 4220                    "".to_string().into(),
 4221                ));
 4222                new_selections.push((
 4223                    Selection {
 4224                        id: selection.id,
 4225                        start: snapshot.anchor_after(emoji_shortcode_start),
 4226                        end: snapshot.anchor_before(selection.start),
 4227                        reversed: selection.reversed,
 4228                        goal: selection.goal,
 4229                    },
 4230                    0,
 4231                ));
 4232
 4233                // Insert emoji
 4234                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4235                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4236                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4237
 4238                continue;
 4239            }
 4240
 4241            // If not handling any auto-close operation, then just replace the selected
 4242            // text with the given input and move the selection to the end of the
 4243            // newly inserted text.
 4244            let anchor = snapshot.anchor_after(selection.end);
 4245            if !self.linked_edit_ranges.is_empty() {
 4246                let start_anchor = snapshot.anchor_before(selection.start);
 4247
 4248                let is_word_char = text.chars().next().is_none_or(|char| {
 4249                    let classifier = snapshot
 4250                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4251                        .ignore_punctuation(true);
 4252                    classifier.is_word(char)
 4253                });
 4254
 4255                if is_word_char {
 4256                    if let Some(ranges) = self
 4257                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4258                    {
 4259                        for (buffer, edits) in ranges {
 4260                            linked_edits
 4261                                .entry(buffer.clone())
 4262                                .or_default()
 4263                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4264                        }
 4265                    }
 4266                } else {
 4267                    clear_linked_edit_ranges = true;
 4268                }
 4269            }
 4270
 4271            new_selections.push((selection.map(|_| anchor), 0));
 4272            edits.push((selection.start..selection.end, text.clone()));
 4273        }
 4274
 4275        drop(snapshot);
 4276
 4277        self.transact(window, cx, |this, window, cx| {
 4278            if clear_linked_edit_ranges {
 4279                this.linked_edit_ranges.clear();
 4280            }
 4281            let initial_buffer_versions =
 4282                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4283
 4284            this.buffer.update(cx, |buffer, cx| {
 4285                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4286            });
 4287            for (buffer, edits) in linked_edits {
 4288                buffer.update(cx, |buffer, cx| {
 4289                    let snapshot = buffer.snapshot();
 4290                    let edits = edits
 4291                        .into_iter()
 4292                        .map(|(range, text)| {
 4293                            use text::ToPoint as TP;
 4294                            let end_point = TP::to_point(&range.end, &snapshot);
 4295                            let start_point = TP::to_point(&range.start, &snapshot);
 4296                            (start_point..end_point, text)
 4297                        })
 4298                        .sorted_by_key(|(range, _)| range.start);
 4299                    buffer.edit(edits, None, cx);
 4300                })
 4301            }
 4302            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4303            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4304            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4305            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4306                .zip(new_selection_deltas)
 4307                .map(|(selection, delta)| Selection {
 4308                    id: selection.id,
 4309                    start: selection.start + delta,
 4310                    end: selection.end + delta,
 4311                    reversed: selection.reversed,
 4312                    goal: SelectionGoal::None,
 4313                })
 4314                .collect::<Vec<_>>();
 4315
 4316            let mut i = 0;
 4317            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4318                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4319                let start = map.buffer_snapshot.anchor_before(position);
 4320                let end = map.buffer_snapshot.anchor_after(position);
 4321                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4322                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4323                        Ordering::Less => i += 1,
 4324                        Ordering::Greater => break,
 4325                        Ordering::Equal => {
 4326                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4327                                Ordering::Less => i += 1,
 4328                                Ordering::Equal => break,
 4329                                Ordering::Greater => break,
 4330                            }
 4331                        }
 4332                    }
 4333                }
 4334                this.autoclose_regions.insert(
 4335                    i,
 4336                    AutocloseRegion {
 4337                        selection_id,
 4338                        range: start..end,
 4339                        pair,
 4340                    },
 4341                );
 4342            }
 4343
 4344            let had_active_edit_prediction = this.has_active_edit_prediction();
 4345            this.change_selections(
 4346                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4347                window,
 4348                cx,
 4349                |s| s.select(new_selections),
 4350            );
 4351
 4352            if !bracket_inserted
 4353                && let Some(on_type_format_task) =
 4354                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4355            {
 4356                on_type_format_task.detach_and_log_err(cx);
 4357            }
 4358
 4359            let editor_settings = EditorSettings::get_global(cx);
 4360            if bracket_inserted
 4361                && (editor_settings.auto_signature_help
 4362                    || editor_settings.show_signature_help_after_edits)
 4363            {
 4364                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4365            }
 4366
 4367            let trigger_in_words =
 4368                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4369            if this.hard_wrap.is_some() {
 4370                let latest: Range<Point> = this.selections.newest(cx).range();
 4371                if latest.is_empty()
 4372                    && this
 4373                        .buffer()
 4374                        .read(cx)
 4375                        .snapshot(cx)
 4376                        .line_len(MultiBufferRow(latest.start.row))
 4377                        == latest.start.column
 4378                {
 4379                    this.rewrap_impl(
 4380                        RewrapOptions {
 4381                            override_language_settings: true,
 4382                            preserve_existing_whitespace: true,
 4383                        },
 4384                        cx,
 4385                    )
 4386                }
 4387            }
 4388            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4389            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4390            this.refresh_edit_prediction(true, false, window, cx);
 4391            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4392        });
 4393    }
 4394
 4395    fn find_possible_emoji_shortcode_at_position(
 4396        snapshot: &MultiBufferSnapshot,
 4397        position: Point,
 4398    ) -> Option<String> {
 4399        let mut chars = Vec::new();
 4400        let mut found_colon = false;
 4401        for char in snapshot.reversed_chars_at(position).take(100) {
 4402            // Found a possible emoji shortcode in the middle of the buffer
 4403            if found_colon {
 4404                if char.is_whitespace() {
 4405                    chars.reverse();
 4406                    return Some(chars.iter().collect());
 4407                }
 4408                // If the previous character is not a whitespace, we are in the middle of a word
 4409                // and we only want to complete the shortcode if the word is made up of other emojis
 4410                let mut containing_word = String::new();
 4411                for ch in snapshot
 4412                    .reversed_chars_at(position)
 4413                    .skip(chars.len() + 1)
 4414                    .take(100)
 4415                {
 4416                    if ch.is_whitespace() {
 4417                        break;
 4418                    }
 4419                    containing_word.push(ch);
 4420                }
 4421                let containing_word = containing_word.chars().rev().collect::<String>();
 4422                if util::word_consists_of_emojis(containing_word.as_str()) {
 4423                    chars.reverse();
 4424                    return Some(chars.iter().collect());
 4425                }
 4426            }
 4427
 4428            if char.is_whitespace() || !char.is_ascii() {
 4429                return None;
 4430            }
 4431            if char == ':' {
 4432                found_colon = true;
 4433            } else {
 4434                chars.push(char);
 4435            }
 4436        }
 4437        // Found a possible emoji shortcode at the beginning of the buffer
 4438        chars.reverse();
 4439        Some(chars.iter().collect())
 4440    }
 4441
 4442    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4443        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4444        self.transact(window, cx, |this, window, cx| {
 4445            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4446                let selections = this.selections.all::<usize>(cx);
 4447                let multi_buffer = this.buffer.read(cx);
 4448                let buffer = multi_buffer.snapshot(cx);
 4449                selections
 4450                    .iter()
 4451                    .map(|selection| {
 4452                        let start_point = selection.start.to_point(&buffer);
 4453                        let mut existing_indent =
 4454                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4455                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4456                        let start = selection.start;
 4457                        let end = selection.end;
 4458                        let selection_is_empty = start == end;
 4459                        let language_scope = buffer.language_scope_at(start);
 4460                        let (
 4461                            comment_delimiter,
 4462                            doc_delimiter,
 4463                            insert_extra_newline,
 4464                            indent_on_newline,
 4465                            indent_on_extra_newline,
 4466                        ) = if let Some(language) = &language_scope {
 4467                            let mut insert_extra_newline =
 4468                                insert_extra_newline_brackets(&buffer, start..end, language)
 4469                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4470
 4471                            // Comment extension on newline is allowed only for cursor selections
 4472                            let comment_delimiter = maybe!({
 4473                                if !selection_is_empty {
 4474                                    return None;
 4475                                }
 4476
 4477                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4478                                    return None;
 4479                                }
 4480
 4481                                let delimiters = language.line_comment_prefixes();
 4482                                let max_len_of_delimiter =
 4483                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4484                                let (snapshot, range) =
 4485                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4486
 4487                                let num_of_whitespaces = snapshot
 4488                                    .chars_for_range(range.clone())
 4489                                    .take_while(|c| c.is_whitespace())
 4490                                    .count();
 4491                                let comment_candidate = snapshot
 4492                                    .chars_for_range(range.clone())
 4493                                    .skip(num_of_whitespaces)
 4494                                    .take(max_len_of_delimiter)
 4495                                    .collect::<String>();
 4496                                let (delimiter, trimmed_len) = delimiters
 4497                                    .iter()
 4498                                    .filter_map(|delimiter| {
 4499                                        let prefix = delimiter.trim_end();
 4500                                        if comment_candidate.starts_with(prefix) {
 4501                                            Some((delimiter, prefix.len()))
 4502                                        } else {
 4503                                            None
 4504                                        }
 4505                                    })
 4506                                    .max_by_key(|(_, len)| *len)?;
 4507
 4508                                if let Some(BlockCommentConfig {
 4509                                    start: block_start, ..
 4510                                }) = language.block_comment()
 4511                                {
 4512                                    let block_start_trimmed = block_start.trim_end();
 4513                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4514                                        let line_content = snapshot
 4515                                            .chars_for_range(range)
 4516                                            .skip(num_of_whitespaces)
 4517                                            .take(block_start_trimmed.len())
 4518                                            .collect::<String>();
 4519
 4520                                        if line_content.starts_with(block_start_trimmed) {
 4521                                            return None;
 4522                                        }
 4523                                    }
 4524                                }
 4525
 4526                                let cursor_is_placed_after_comment_marker =
 4527                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4528                                if cursor_is_placed_after_comment_marker {
 4529                                    Some(delimiter.clone())
 4530                                } else {
 4531                                    None
 4532                                }
 4533                            });
 4534
 4535                            let mut indent_on_newline = IndentSize::spaces(0);
 4536                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4537
 4538                            let doc_delimiter = maybe!({
 4539                                if !selection_is_empty {
 4540                                    return None;
 4541                                }
 4542
 4543                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4544                                    return None;
 4545                                }
 4546
 4547                                let BlockCommentConfig {
 4548                                    start: start_tag,
 4549                                    end: end_tag,
 4550                                    prefix: delimiter,
 4551                                    tab_size: len,
 4552                                } = language.documentation_comment()?;
 4553                                let is_within_block_comment = buffer
 4554                                    .language_scope_at(start_point)
 4555                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4556                                if !is_within_block_comment {
 4557                                    return None;
 4558                                }
 4559
 4560                                let (snapshot, range) =
 4561                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4562
 4563                                let num_of_whitespaces = snapshot
 4564                                    .chars_for_range(range.clone())
 4565                                    .take_while(|c| c.is_whitespace())
 4566                                    .count();
 4567
 4568                                // 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.
 4569                                let column = start_point.column;
 4570                                let cursor_is_after_start_tag = {
 4571                                    let start_tag_len = start_tag.len();
 4572                                    let start_tag_line = snapshot
 4573                                        .chars_for_range(range.clone())
 4574                                        .skip(num_of_whitespaces)
 4575                                        .take(start_tag_len)
 4576                                        .collect::<String>();
 4577                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4578                                        num_of_whitespaces + start_tag_len <= column as usize
 4579                                    } else {
 4580                                        false
 4581                                    }
 4582                                };
 4583
 4584                                let cursor_is_after_delimiter = {
 4585                                    let delimiter_trim = delimiter.trim_end();
 4586                                    let delimiter_line = snapshot
 4587                                        .chars_for_range(range.clone())
 4588                                        .skip(num_of_whitespaces)
 4589                                        .take(delimiter_trim.len())
 4590                                        .collect::<String>();
 4591                                    if delimiter_line.starts_with(delimiter_trim) {
 4592                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4593                                    } else {
 4594                                        false
 4595                                    }
 4596                                };
 4597
 4598                                let cursor_is_before_end_tag_if_exists = {
 4599                                    let mut char_position = 0u32;
 4600                                    let mut end_tag_offset = None;
 4601
 4602                                    'outer: for chunk in snapshot.text_for_range(range) {
 4603                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4604                                            let chars_before_match =
 4605                                                chunk[..byte_pos].chars().count() as u32;
 4606                                            end_tag_offset =
 4607                                                Some(char_position + chars_before_match);
 4608                                            break 'outer;
 4609                                        }
 4610                                        char_position += chunk.chars().count() as u32;
 4611                                    }
 4612
 4613                                    if let Some(end_tag_offset) = end_tag_offset {
 4614                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4615                                        if cursor_is_after_start_tag {
 4616                                            if cursor_is_before_end_tag {
 4617                                                insert_extra_newline = true;
 4618                                            }
 4619                                            let cursor_is_at_start_of_end_tag =
 4620                                                column == end_tag_offset;
 4621                                            if cursor_is_at_start_of_end_tag {
 4622                                                indent_on_extra_newline.len = *len;
 4623                                            }
 4624                                        }
 4625                                        cursor_is_before_end_tag
 4626                                    } else {
 4627                                        true
 4628                                    }
 4629                                };
 4630
 4631                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4632                                    && cursor_is_before_end_tag_if_exists
 4633                                {
 4634                                    if cursor_is_after_start_tag {
 4635                                        indent_on_newline.len = *len;
 4636                                    }
 4637                                    Some(delimiter.clone())
 4638                                } else {
 4639                                    None
 4640                                }
 4641                            });
 4642
 4643                            (
 4644                                comment_delimiter,
 4645                                doc_delimiter,
 4646                                insert_extra_newline,
 4647                                indent_on_newline,
 4648                                indent_on_extra_newline,
 4649                            )
 4650                        } else {
 4651                            (
 4652                                None,
 4653                                None,
 4654                                false,
 4655                                IndentSize::default(),
 4656                                IndentSize::default(),
 4657                            )
 4658                        };
 4659
 4660                        let prevent_auto_indent = doc_delimiter.is_some();
 4661                        let delimiter = comment_delimiter.or(doc_delimiter);
 4662
 4663                        let capacity_for_delimiter =
 4664                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4665                        let mut new_text = String::with_capacity(
 4666                            1 + capacity_for_delimiter
 4667                                + existing_indent.len as usize
 4668                                + indent_on_newline.len as usize
 4669                                + indent_on_extra_newline.len as usize,
 4670                        );
 4671                        new_text.push('\n');
 4672                        new_text.extend(existing_indent.chars());
 4673                        new_text.extend(indent_on_newline.chars());
 4674
 4675                        if let Some(delimiter) = &delimiter {
 4676                            new_text.push_str(delimiter);
 4677                        }
 4678
 4679                        if insert_extra_newline {
 4680                            new_text.push('\n');
 4681                            new_text.extend(existing_indent.chars());
 4682                            new_text.extend(indent_on_extra_newline.chars());
 4683                        }
 4684
 4685                        let anchor = buffer.anchor_after(end);
 4686                        let new_selection = selection.map(|_| anchor);
 4687                        (
 4688                            ((start..end, new_text), prevent_auto_indent),
 4689                            (insert_extra_newline, new_selection),
 4690                        )
 4691                    })
 4692                    .unzip()
 4693            };
 4694
 4695            let mut auto_indent_edits = Vec::new();
 4696            let mut edits = Vec::new();
 4697            for (edit, prevent_auto_indent) in edits_with_flags {
 4698                if prevent_auto_indent {
 4699                    edits.push(edit);
 4700                } else {
 4701                    auto_indent_edits.push(edit);
 4702                }
 4703            }
 4704            if !edits.is_empty() {
 4705                this.edit(edits, cx);
 4706            }
 4707            if !auto_indent_edits.is_empty() {
 4708                this.edit_with_autoindent(auto_indent_edits, cx);
 4709            }
 4710
 4711            let buffer = this.buffer.read(cx).snapshot(cx);
 4712            let new_selections = selection_info
 4713                .into_iter()
 4714                .map(|(extra_newline_inserted, new_selection)| {
 4715                    let mut cursor = new_selection.end.to_point(&buffer);
 4716                    if extra_newline_inserted {
 4717                        cursor.row -= 1;
 4718                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4719                    }
 4720                    new_selection.map(|_| cursor)
 4721                })
 4722                .collect();
 4723
 4724            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4725            this.refresh_edit_prediction(true, false, window, cx);
 4726        });
 4727    }
 4728
 4729    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4730        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4731
 4732        let buffer = self.buffer.read(cx);
 4733        let snapshot = buffer.snapshot(cx);
 4734
 4735        let mut edits = Vec::new();
 4736        let mut rows = Vec::new();
 4737
 4738        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4739            let cursor = selection.head();
 4740            let row = cursor.row;
 4741
 4742            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4743
 4744            let newline = "\n".to_string();
 4745            edits.push((start_of_line..start_of_line, newline));
 4746
 4747            rows.push(row + rows_inserted as u32);
 4748        }
 4749
 4750        self.transact(window, cx, |editor, window, cx| {
 4751            editor.edit(edits, cx);
 4752
 4753            editor.change_selections(Default::default(), window, cx, |s| {
 4754                let mut index = 0;
 4755                s.move_cursors_with(|map, _, _| {
 4756                    let row = rows[index];
 4757                    index += 1;
 4758
 4759                    let point = Point::new(row, 0);
 4760                    let boundary = map.next_line_boundary(point).1;
 4761                    let clipped = map.clip_point(boundary, Bias::Left);
 4762
 4763                    (clipped, SelectionGoal::None)
 4764                });
 4765            });
 4766
 4767            let mut indent_edits = Vec::new();
 4768            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4769            for row in rows {
 4770                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4771                for (row, indent) in indents {
 4772                    if indent.len == 0 {
 4773                        continue;
 4774                    }
 4775
 4776                    let text = match indent.kind {
 4777                        IndentKind::Space => " ".repeat(indent.len as usize),
 4778                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4779                    };
 4780                    let point = Point::new(row.0, 0);
 4781                    indent_edits.push((point..point, text));
 4782                }
 4783            }
 4784            editor.edit(indent_edits, cx);
 4785        });
 4786    }
 4787
 4788    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4790
 4791        let buffer = self.buffer.read(cx);
 4792        let snapshot = buffer.snapshot(cx);
 4793
 4794        let mut edits = Vec::new();
 4795        let mut rows = Vec::new();
 4796        let mut rows_inserted = 0;
 4797
 4798        for selection in self.selections.all_adjusted(cx) {
 4799            let cursor = selection.head();
 4800            let row = cursor.row;
 4801
 4802            let point = Point::new(row + 1, 0);
 4803            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4804
 4805            let newline = "\n".to_string();
 4806            edits.push((start_of_line..start_of_line, newline));
 4807
 4808            rows_inserted += 1;
 4809            rows.push(row + rows_inserted);
 4810        }
 4811
 4812        self.transact(window, cx, |editor, window, cx| {
 4813            editor.edit(edits, cx);
 4814
 4815            editor.change_selections(Default::default(), window, cx, |s| {
 4816                let mut index = 0;
 4817                s.move_cursors_with(|map, _, _| {
 4818                    let row = rows[index];
 4819                    index += 1;
 4820
 4821                    let point = Point::new(row, 0);
 4822                    let boundary = map.next_line_boundary(point).1;
 4823                    let clipped = map.clip_point(boundary, Bias::Left);
 4824
 4825                    (clipped, SelectionGoal::None)
 4826                });
 4827            });
 4828
 4829            let mut indent_edits = Vec::new();
 4830            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4831            for row in rows {
 4832                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4833                for (row, indent) in indents {
 4834                    if indent.len == 0 {
 4835                        continue;
 4836                    }
 4837
 4838                    let text = match indent.kind {
 4839                        IndentKind::Space => " ".repeat(indent.len as usize),
 4840                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4841                    };
 4842                    let point = Point::new(row.0, 0);
 4843                    indent_edits.push((point..point, text));
 4844                }
 4845            }
 4846            editor.edit(indent_edits, cx);
 4847        });
 4848    }
 4849
 4850    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4851        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4852            original_indent_columns: Vec::new(),
 4853        });
 4854        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4855    }
 4856
 4857    fn insert_with_autoindent_mode(
 4858        &mut self,
 4859        text: &str,
 4860        autoindent_mode: Option<AutoindentMode>,
 4861        window: &mut Window,
 4862        cx: &mut Context<Self>,
 4863    ) {
 4864        if self.read_only(cx) {
 4865            return;
 4866        }
 4867
 4868        let text: Arc<str> = text.into();
 4869        self.transact(window, cx, |this, window, cx| {
 4870            let old_selections = this.selections.all_adjusted(cx);
 4871            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4872                let anchors = {
 4873                    let snapshot = buffer.read(cx);
 4874                    old_selections
 4875                        .iter()
 4876                        .map(|s| {
 4877                            let anchor = snapshot.anchor_after(s.head());
 4878                            s.map(|_| anchor)
 4879                        })
 4880                        .collect::<Vec<_>>()
 4881                };
 4882                buffer.edit(
 4883                    old_selections
 4884                        .iter()
 4885                        .map(|s| (s.start..s.end, text.clone())),
 4886                    autoindent_mode,
 4887                    cx,
 4888                );
 4889                anchors
 4890            });
 4891
 4892            this.change_selections(Default::default(), window, cx, |s| {
 4893                s.select_anchors(selection_anchors);
 4894            });
 4895
 4896            cx.notify();
 4897        });
 4898    }
 4899
 4900    fn trigger_completion_on_input(
 4901        &mut self,
 4902        text: &str,
 4903        trigger_in_words: bool,
 4904        window: &mut Window,
 4905        cx: &mut Context<Self>,
 4906    ) {
 4907        let completions_source = self
 4908            .context_menu
 4909            .borrow()
 4910            .as_ref()
 4911            .and_then(|menu| match menu {
 4912                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4913                CodeContextMenu::CodeActions(_) => None,
 4914            });
 4915
 4916        match completions_source {
 4917            Some(CompletionsMenuSource::Words { .. }) => {
 4918                self.open_or_update_completions_menu(
 4919                    Some(CompletionsMenuSource::Words {
 4920                        ignore_threshold: false,
 4921                    }),
 4922                    None,
 4923                    window,
 4924                    cx,
 4925                );
 4926            }
 4927            Some(CompletionsMenuSource::Normal)
 4928            | Some(CompletionsMenuSource::SnippetChoices)
 4929            | None
 4930                if self.is_completion_trigger(
 4931                    text,
 4932                    trigger_in_words,
 4933                    completions_source.is_some(),
 4934                    cx,
 4935                ) =>
 4936            {
 4937                self.show_completions(
 4938                    &ShowCompletions {
 4939                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4940                    },
 4941                    window,
 4942                    cx,
 4943                )
 4944            }
 4945            _ => {
 4946                self.hide_context_menu(window, cx);
 4947            }
 4948        }
 4949    }
 4950
 4951    fn is_completion_trigger(
 4952        &self,
 4953        text: &str,
 4954        trigger_in_words: bool,
 4955        menu_is_open: bool,
 4956        cx: &mut Context<Self>,
 4957    ) -> bool {
 4958        let position = self.selections.newest_anchor().head();
 4959        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 4960            return false;
 4961        };
 4962
 4963        if let Some(completion_provider) = &self.completion_provider {
 4964            completion_provider.is_completion_trigger(
 4965                &buffer,
 4966                position.text_anchor,
 4967                text,
 4968                trigger_in_words,
 4969                menu_is_open,
 4970                cx,
 4971            )
 4972        } else {
 4973            false
 4974        }
 4975    }
 4976
 4977    /// If any empty selections is touching the start of its innermost containing autoclose
 4978    /// region, expand it to select the brackets.
 4979    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4980        let selections = self.selections.all::<usize>(cx);
 4981        let buffer = self.buffer.read(cx).read(cx);
 4982        let new_selections = self
 4983            .selections_with_autoclose_regions(selections, &buffer)
 4984            .map(|(mut selection, region)| {
 4985                if !selection.is_empty() {
 4986                    return selection;
 4987                }
 4988
 4989                if let Some(region) = region {
 4990                    let mut range = region.range.to_offset(&buffer);
 4991                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4992                        range.start -= region.pair.start.len();
 4993                        if buffer.contains_str_at(range.start, &region.pair.start)
 4994                            && buffer.contains_str_at(range.end, &region.pair.end)
 4995                        {
 4996                            range.end += region.pair.end.len();
 4997                            selection.start = range.start;
 4998                            selection.end = range.end;
 4999
 5000                            return selection;
 5001                        }
 5002                    }
 5003                }
 5004
 5005                let always_treat_brackets_as_autoclosed = buffer
 5006                    .language_settings_at(selection.start, cx)
 5007                    .always_treat_brackets_as_autoclosed;
 5008
 5009                if !always_treat_brackets_as_autoclosed {
 5010                    return selection;
 5011                }
 5012
 5013                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5014                    for (pair, enabled) in scope.brackets() {
 5015                        if !enabled || !pair.close {
 5016                            continue;
 5017                        }
 5018
 5019                        if buffer.contains_str_at(selection.start, &pair.end) {
 5020                            let pair_start_len = pair.start.len();
 5021                            if buffer.contains_str_at(
 5022                                selection.start.saturating_sub(pair_start_len),
 5023                                &pair.start,
 5024                            ) {
 5025                                selection.start -= pair_start_len;
 5026                                selection.end += pair.end.len();
 5027
 5028                                return selection;
 5029                            }
 5030                        }
 5031                    }
 5032                }
 5033
 5034                selection
 5035            })
 5036            .collect();
 5037
 5038        drop(buffer);
 5039        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5040            selections.select(new_selections)
 5041        });
 5042    }
 5043
 5044    /// Iterate the given selections, and for each one, find the smallest surrounding
 5045    /// autoclose region. This uses the ordering of the selections and the autoclose
 5046    /// regions to avoid repeated comparisons.
 5047    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5048        &'a self,
 5049        selections: impl IntoIterator<Item = Selection<D>>,
 5050        buffer: &'a MultiBufferSnapshot,
 5051    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5052        let mut i = 0;
 5053        let mut regions = self.autoclose_regions.as_slice();
 5054        selections.into_iter().map(move |selection| {
 5055            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5056
 5057            let mut enclosing = None;
 5058            while let Some(pair_state) = regions.get(i) {
 5059                if pair_state.range.end.to_offset(buffer) < range.start {
 5060                    regions = &regions[i + 1..];
 5061                    i = 0;
 5062                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5063                    break;
 5064                } else {
 5065                    if pair_state.selection_id == selection.id {
 5066                        enclosing = Some(pair_state);
 5067                    }
 5068                    i += 1;
 5069                }
 5070            }
 5071
 5072            (selection, enclosing)
 5073        })
 5074    }
 5075
 5076    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5077    fn invalidate_autoclose_regions(
 5078        &mut self,
 5079        mut selections: &[Selection<Anchor>],
 5080        buffer: &MultiBufferSnapshot,
 5081    ) {
 5082        self.autoclose_regions.retain(|state| {
 5083            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5084                return false;
 5085            }
 5086
 5087            let mut i = 0;
 5088            while let Some(selection) = selections.get(i) {
 5089                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5090                    selections = &selections[1..];
 5091                    continue;
 5092                }
 5093                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5094                    break;
 5095                }
 5096                if selection.id == state.selection_id {
 5097                    return true;
 5098                } else {
 5099                    i += 1;
 5100                }
 5101            }
 5102            false
 5103        });
 5104    }
 5105
 5106    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5107        let offset = position.to_offset(buffer);
 5108        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5109        if offset > word_range.start && kind == Some(CharKind::Word) {
 5110            Some(
 5111                buffer
 5112                    .text_for_range(word_range.start..offset)
 5113                    .collect::<String>(),
 5114            )
 5115        } else {
 5116            None
 5117        }
 5118    }
 5119
 5120    pub fn toggle_inline_values(
 5121        &mut self,
 5122        _: &ToggleInlineValues,
 5123        _: &mut Window,
 5124        cx: &mut Context<Self>,
 5125    ) {
 5126        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5127
 5128        self.refresh_inline_values(cx);
 5129    }
 5130
 5131    pub fn toggle_inlay_hints(
 5132        &mut self,
 5133        _: &ToggleInlayHints,
 5134        _: &mut Window,
 5135        cx: &mut Context<Self>,
 5136    ) {
 5137        self.refresh_inlay_hints(
 5138            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5139            cx,
 5140        );
 5141    }
 5142
 5143    pub fn inlay_hints_enabled(&self) -> bool {
 5144        self.inlay_hint_cache.enabled
 5145    }
 5146
 5147    pub fn inline_values_enabled(&self) -> bool {
 5148        self.inline_value_cache.enabled
 5149    }
 5150
 5151    #[cfg(any(test, feature = "test-support"))]
 5152    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5153        self.display_map
 5154            .read(cx)
 5155            .current_inlays()
 5156            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5157            .cloned()
 5158            .collect()
 5159    }
 5160
 5161    #[cfg(any(test, feature = "test-support"))]
 5162    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5163        self.display_map
 5164            .read(cx)
 5165            .current_inlays()
 5166            .cloned()
 5167            .collect()
 5168    }
 5169
 5170    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5171        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5172            return;
 5173        }
 5174
 5175        let reason_description = reason.description();
 5176        let ignore_debounce = matches!(
 5177            reason,
 5178            InlayHintRefreshReason::SettingsChange(_)
 5179                | InlayHintRefreshReason::Toggle(_)
 5180                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5181                | InlayHintRefreshReason::ModifiersChanged(_)
 5182        );
 5183        let (invalidate_cache, required_languages) = match reason {
 5184            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5185                match self.inlay_hint_cache.modifiers_override(enabled) {
 5186                    Some(enabled) => {
 5187                        if enabled {
 5188                            (InvalidationStrategy::RefreshRequested, None)
 5189                        } else {
 5190                            self.splice_inlays(
 5191                                &self
 5192                                    .visible_inlay_hints(cx)
 5193                                    .iter()
 5194                                    .map(|inlay| inlay.id)
 5195                                    .collect::<Vec<InlayId>>(),
 5196                                Vec::new(),
 5197                                cx,
 5198                            );
 5199                            return;
 5200                        }
 5201                    }
 5202                    None => return,
 5203                }
 5204            }
 5205            InlayHintRefreshReason::Toggle(enabled) => {
 5206                if self.inlay_hint_cache.toggle(enabled) {
 5207                    if enabled {
 5208                        (InvalidationStrategy::RefreshRequested, None)
 5209                    } else {
 5210                        self.splice_inlays(
 5211                            &self
 5212                                .visible_inlay_hints(cx)
 5213                                .iter()
 5214                                .map(|inlay| inlay.id)
 5215                                .collect::<Vec<InlayId>>(),
 5216                            Vec::new(),
 5217                            cx,
 5218                        );
 5219                        return;
 5220                    }
 5221                } else {
 5222                    return;
 5223                }
 5224            }
 5225            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5226                match self.inlay_hint_cache.update_settings(
 5227                    &self.buffer,
 5228                    new_settings,
 5229                    self.visible_inlay_hints(cx),
 5230                    cx,
 5231                ) {
 5232                    ControlFlow::Break(Some(InlaySplice {
 5233                        to_remove,
 5234                        to_insert,
 5235                    })) => {
 5236                        self.splice_inlays(&to_remove, to_insert, cx);
 5237                        return;
 5238                    }
 5239                    ControlFlow::Break(None) => return,
 5240                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5241                }
 5242            }
 5243            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5244                if let Some(InlaySplice {
 5245                    to_remove,
 5246                    to_insert,
 5247                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5248                {
 5249                    self.splice_inlays(&to_remove, to_insert, cx);
 5250                }
 5251                self.display_map.update(cx, |display_map, _| {
 5252                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5253                });
 5254                return;
 5255            }
 5256            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5257            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5258                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5259            }
 5260            InlayHintRefreshReason::RefreshRequested => {
 5261                (InvalidationStrategy::RefreshRequested, None)
 5262            }
 5263        };
 5264
 5265        if let Some(InlaySplice {
 5266            to_remove,
 5267            to_insert,
 5268        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5269            reason_description,
 5270            self.visible_excerpts(required_languages.as_ref(), cx),
 5271            invalidate_cache,
 5272            ignore_debounce,
 5273            cx,
 5274        ) {
 5275            self.splice_inlays(&to_remove, to_insert, cx);
 5276        }
 5277    }
 5278
 5279    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5280        self.display_map
 5281            .read(cx)
 5282            .current_inlays()
 5283            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5284            .cloned()
 5285            .collect()
 5286    }
 5287
 5288    pub fn visible_excerpts(
 5289        &self,
 5290        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5291        cx: &mut Context<Editor>,
 5292    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5293        let Some(project) = self.project() else {
 5294            return HashMap::default();
 5295        };
 5296        let project = project.read(cx);
 5297        let multi_buffer = self.buffer().read(cx);
 5298        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5299        let multi_buffer_visible_start = self
 5300            .scroll_manager
 5301            .anchor()
 5302            .anchor
 5303            .to_point(&multi_buffer_snapshot);
 5304        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5305            multi_buffer_visible_start
 5306                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5307            Bias::Left,
 5308        );
 5309        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5310        multi_buffer_snapshot
 5311            .range_to_buffer_ranges(multi_buffer_visible_range)
 5312            .into_iter()
 5313            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5314            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5315                let buffer_file = project::File::from_dyn(buffer.file())?;
 5316                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5317                let worktree_entry = buffer_worktree
 5318                    .read(cx)
 5319                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5320                if worktree_entry.is_ignored {
 5321                    return None;
 5322                }
 5323
 5324                let language = buffer.language()?;
 5325                if let Some(restrict_to_languages) = restrict_to_languages
 5326                    && !restrict_to_languages.contains(language)
 5327                {
 5328                    return None;
 5329                }
 5330                Some((
 5331                    excerpt_id,
 5332                    (
 5333                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5334                        buffer.version().clone(),
 5335                        excerpt_visible_range,
 5336                    ),
 5337                ))
 5338            })
 5339            .collect()
 5340    }
 5341
 5342    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5343        TextLayoutDetails {
 5344            text_system: window.text_system().clone(),
 5345            editor_style: self.style.clone().unwrap(),
 5346            rem_size: window.rem_size(),
 5347            scroll_anchor: self.scroll_manager.anchor(),
 5348            visible_rows: self.visible_line_count(),
 5349            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5350        }
 5351    }
 5352
 5353    pub fn splice_inlays(
 5354        &self,
 5355        to_remove: &[InlayId],
 5356        to_insert: Vec<Inlay>,
 5357        cx: &mut Context<Self>,
 5358    ) {
 5359        self.display_map.update(cx, |display_map, cx| {
 5360            display_map.splice_inlays(to_remove, to_insert, cx)
 5361        });
 5362        cx.notify();
 5363    }
 5364
 5365    fn trigger_on_type_formatting(
 5366        &self,
 5367        input: String,
 5368        window: &mut Window,
 5369        cx: &mut Context<Self>,
 5370    ) -> Option<Task<Result<()>>> {
 5371        if input.len() != 1 {
 5372            return None;
 5373        }
 5374
 5375        let project = self.project()?;
 5376        let position = self.selections.newest_anchor().head();
 5377        let (buffer, buffer_position) = self
 5378            .buffer
 5379            .read(cx)
 5380            .text_anchor_for_position(position, cx)?;
 5381
 5382        let settings = language_settings::language_settings(
 5383            buffer
 5384                .read(cx)
 5385                .language_at(buffer_position)
 5386                .map(|l| l.name()),
 5387            buffer.read(cx).file(),
 5388            cx,
 5389        );
 5390        if !settings.use_on_type_format {
 5391            return None;
 5392        }
 5393
 5394        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5395        // hence we do LSP request & edit on host side only — add formats to host's history.
 5396        let push_to_lsp_host_history = true;
 5397        // If this is not the host, append its history with new edits.
 5398        let push_to_client_history = project.read(cx).is_via_collab();
 5399
 5400        let on_type_formatting = project.update(cx, |project, cx| {
 5401            project.on_type_format(
 5402                buffer.clone(),
 5403                buffer_position,
 5404                input,
 5405                push_to_lsp_host_history,
 5406                cx,
 5407            )
 5408        });
 5409        Some(cx.spawn_in(window, async move |editor, cx| {
 5410            if let Some(transaction) = on_type_formatting.await? {
 5411                if push_to_client_history {
 5412                    buffer
 5413                        .update(cx, |buffer, _| {
 5414                            buffer.push_transaction(transaction, Instant::now());
 5415                            buffer.finalize_last_transaction();
 5416                        })
 5417                        .ok();
 5418                }
 5419                editor.update(cx, |editor, cx| {
 5420                    editor.refresh_document_highlights(cx);
 5421                })?;
 5422            }
 5423            Ok(())
 5424        }))
 5425    }
 5426
 5427    pub fn show_word_completions(
 5428        &mut self,
 5429        _: &ShowWordCompletions,
 5430        window: &mut Window,
 5431        cx: &mut Context<Self>,
 5432    ) {
 5433        self.open_or_update_completions_menu(
 5434            Some(CompletionsMenuSource::Words {
 5435                ignore_threshold: true,
 5436            }),
 5437            None,
 5438            window,
 5439            cx,
 5440        );
 5441    }
 5442
 5443    pub fn show_completions(
 5444        &mut self,
 5445        options: &ShowCompletions,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) {
 5449        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5450    }
 5451
 5452    fn open_or_update_completions_menu(
 5453        &mut self,
 5454        requested_source: Option<CompletionsMenuSource>,
 5455        trigger: Option<&str>,
 5456        window: &mut Window,
 5457        cx: &mut Context<Self>,
 5458    ) {
 5459        if self.pending_rename.is_some() {
 5460            return;
 5461        }
 5462
 5463        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5464
 5465        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5466        // inserted and selected. To handle that case, the start of the selection is used so that
 5467        // the menu starts with all choices.
 5468        let position = self
 5469            .selections
 5470            .newest_anchor()
 5471            .start
 5472            .bias_right(&multibuffer_snapshot);
 5473        if position.diff_base_anchor.is_some() {
 5474            return;
 5475        }
 5476        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5477        let Some(buffer) = buffer_position
 5478            .buffer_id
 5479            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5480        else {
 5481            return;
 5482        };
 5483        let buffer_snapshot = buffer.read(cx).snapshot();
 5484
 5485        let query: Option<Arc<String>> =
 5486            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5487                .map(|query| query.into());
 5488
 5489        drop(multibuffer_snapshot);
 5490
 5491        // Hide the current completions menu when query is empty. Without this, cached
 5492        // completions from before the trigger char may be reused (#32774).
 5493        if query.is_none() {
 5494            let menu_is_open = matches!(
 5495                self.context_menu.borrow().as_ref(),
 5496                Some(CodeContextMenu::Completions(_))
 5497            );
 5498            if menu_is_open {
 5499                self.hide_context_menu(window, cx);
 5500            }
 5501        }
 5502
 5503        let mut ignore_word_threshold = false;
 5504        let provider = match requested_source {
 5505            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5506            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5507                ignore_word_threshold = ignore_threshold;
 5508                None
 5509            }
 5510            Some(CompletionsMenuSource::SnippetChoices) => {
 5511                log::error!("bug: SnippetChoices requested_source is not handled");
 5512                None
 5513            }
 5514        };
 5515
 5516        let sort_completions = provider
 5517            .as_ref()
 5518            .is_some_and(|provider| provider.sort_completions());
 5519
 5520        let filter_completions = provider
 5521            .as_ref()
 5522            .is_none_or(|provider| provider.filter_completions());
 5523
 5524        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5525            if filter_completions {
 5526                menu.filter(query.clone(), provider.clone(), window, cx);
 5527            }
 5528            // When `is_incomplete` is false, no need to re-query completions when the current query
 5529            // is a suffix of the initial query.
 5530            if !menu.is_incomplete {
 5531                // If the new query is a suffix of the old query (typing more characters) and
 5532                // the previous result was complete, the existing completions can be filtered.
 5533                //
 5534                // Note that this is always true for snippet completions.
 5535                let query_matches = match (&menu.initial_query, &query) {
 5536                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5537                    (None, _) => true,
 5538                    _ => false,
 5539                };
 5540                if query_matches {
 5541                    let position_matches = if menu.initial_position == position {
 5542                        true
 5543                    } else {
 5544                        let snapshot = self.buffer.read(cx).read(cx);
 5545                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5546                    };
 5547                    if position_matches {
 5548                        return;
 5549                    }
 5550                }
 5551            }
 5552        };
 5553
 5554        let trigger_kind = match trigger {
 5555            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5556                CompletionTriggerKind::TRIGGER_CHARACTER
 5557            }
 5558            _ => CompletionTriggerKind::INVOKED,
 5559        };
 5560        let completion_context = CompletionContext {
 5561            trigger_character: trigger.and_then(|trigger| {
 5562                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5563                    Some(String::from(trigger))
 5564                } else {
 5565                    None
 5566                }
 5567            }),
 5568            trigger_kind,
 5569        };
 5570
 5571        let Anchor {
 5572            excerpt_id: buffer_excerpt_id,
 5573            text_anchor: buffer_position,
 5574            ..
 5575        } = buffer_position;
 5576
 5577        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5578            buffer_snapshot.surrounding_word(buffer_position, false)
 5579        {
 5580            let word_to_exclude = buffer_snapshot
 5581                .text_for_range(word_range.clone())
 5582                .collect::<String>();
 5583            (
 5584                buffer_snapshot.anchor_before(word_range.start)
 5585                    ..buffer_snapshot.anchor_after(buffer_position),
 5586                Some(word_to_exclude),
 5587            )
 5588        } else {
 5589            (buffer_position..buffer_position, None)
 5590        };
 5591
 5592        let language = buffer_snapshot
 5593            .language_at(buffer_position)
 5594            .map(|language| language.name());
 5595
 5596        let completion_settings =
 5597            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5598
 5599        let show_completion_documentation = buffer_snapshot
 5600            .settings_at(buffer_position, cx)
 5601            .show_completion_documentation;
 5602
 5603        // The document can be large, so stay in reasonable bounds when searching for words,
 5604        // otherwise completion pop-up might be slow to appear.
 5605        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5606        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5607        let min_word_search = buffer_snapshot.clip_point(
 5608            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5609            Bias::Left,
 5610        );
 5611        let max_word_search = buffer_snapshot.clip_point(
 5612            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5613            Bias::Right,
 5614        );
 5615        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5616            ..buffer_snapshot.point_to_offset(max_word_search);
 5617
 5618        let skip_digits = query
 5619            .as_ref()
 5620            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5621
 5622        let omit_word_completions = !self.word_completions_enabled
 5623            || (!ignore_word_threshold
 5624                && match &query {
 5625                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5626                    None => completion_settings.words_min_length != 0,
 5627                });
 5628
 5629        let (mut words, provider_responses) = match &provider {
 5630            Some(provider) => {
 5631                let provider_responses = provider.completions(
 5632                    buffer_excerpt_id,
 5633                    &buffer,
 5634                    buffer_position,
 5635                    completion_context,
 5636                    window,
 5637                    cx,
 5638                );
 5639
 5640                let words = match (omit_word_completions, completion_settings.words) {
 5641                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5642                        Task::ready(BTreeMap::default())
 5643                    }
 5644                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5645                        .background_spawn(async move {
 5646                            buffer_snapshot.words_in_range(WordsQuery {
 5647                                fuzzy_contents: None,
 5648                                range: word_search_range,
 5649                                skip_digits,
 5650                            })
 5651                        }),
 5652                };
 5653
 5654                (words, provider_responses)
 5655            }
 5656            None => {
 5657                let words = if omit_word_completions {
 5658                    Task::ready(BTreeMap::default())
 5659                } else {
 5660                    cx.background_spawn(async move {
 5661                        buffer_snapshot.words_in_range(WordsQuery {
 5662                            fuzzy_contents: None,
 5663                            range: word_search_range,
 5664                            skip_digits,
 5665                        })
 5666                    })
 5667                };
 5668                (words, Task::ready(Ok(Vec::new())))
 5669            }
 5670        };
 5671
 5672        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5673
 5674        let id = post_inc(&mut self.next_completion_id);
 5675        let task = cx.spawn_in(window, async move |editor, cx| {
 5676            let Ok(()) = editor.update(cx, |this, _| {
 5677                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5678            }) else {
 5679                return;
 5680            };
 5681
 5682            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5683            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5684            let mut completions = Vec::new();
 5685            let mut is_incomplete = false;
 5686            let mut display_options: Option<CompletionDisplayOptions> = None;
 5687            if let Some(provider_responses) = provider_responses.await.log_err()
 5688                && !provider_responses.is_empty()
 5689            {
 5690                for response in provider_responses {
 5691                    completions.extend(response.completions);
 5692                    is_incomplete = is_incomplete || response.is_incomplete;
 5693                    match display_options.as_mut() {
 5694                        None => {
 5695                            display_options = Some(response.display_options);
 5696                        }
 5697                        Some(options) => options.merge(&response.display_options),
 5698                    }
 5699                }
 5700                if completion_settings.words == WordsCompletionMode::Fallback {
 5701                    words = Task::ready(BTreeMap::default());
 5702                }
 5703            }
 5704            let display_options = display_options.unwrap_or_default();
 5705
 5706            let mut words = words.await;
 5707            if let Some(word_to_exclude) = &word_to_exclude {
 5708                words.remove(word_to_exclude);
 5709            }
 5710            for lsp_completion in &completions {
 5711                words.remove(&lsp_completion.new_text);
 5712            }
 5713            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5714                replace_range: word_replace_range.clone(),
 5715                new_text: word.clone(),
 5716                label: CodeLabel::plain(word, None),
 5717                icon_path: None,
 5718                documentation: None,
 5719                source: CompletionSource::BufferWord {
 5720                    word_range,
 5721                    resolved: false,
 5722                },
 5723                insert_text_mode: Some(InsertTextMode::AS_IS),
 5724                confirm: None,
 5725            }));
 5726
 5727            let menu = if completions.is_empty() {
 5728                None
 5729            } else {
 5730                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5731                    let languages = editor
 5732                        .workspace
 5733                        .as_ref()
 5734                        .and_then(|(workspace, _)| workspace.upgrade())
 5735                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5736                    let menu = CompletionsMenu::new(
 5737                        id,
 5738                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5739                        sort_completions,
 5740                        show_completion_documentation,
 5741                        position,
 5742                        query.clone(),
 5743                        is_incomplete,
 5744                        buffer.clone(),
 5745                        completions.into(),
 5746                        display_options,
 5747                        snippet_sort_order,
 5748                        languages,
 5749                        language,
 5750                        cx,
 5751                    );
 5752
 5753                    let query = if filter_completions { query } else { None };
 5754                    let matches_task = if let Some(query) = query {
 5755                        menu.do_async_filtering(query, cx)
 5756                    } else {
 5757                        Task::ready(menu.unfiltered_matches())
 5758                    };
 5759                    (menu, matches_task)
 5760                }) else {
 5761                    return;
 5762                };
 5763
 5764                let matches = matches_task.await;
 5765
 5766                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5767                    // Newer menu already set, so exit.
 5768                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5769                        editor.context_menu.borrow().as_ref()
 5770                        && prev_menu.id > id
 5771                    {
 5772                        return;
 5773                    };
 5774
 5775                    // Only valid to take prev_menu because it the new menu is immediately set
 5776                    // below, or the menu is hidden.
 5777                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5778                        editor.context_menu.borrow_mut().take()
 5779                    {
 5780                        let position_matches =
 5781                            if prev_menu.initial_position == menu.initial_position {
 5782                                true
 5783                            } else {
 5784                                let snapshot = editor.buffer.read(cx).read(cx);
 5785                                prev_menu.initial_position.to_offset(&snapshot)
 5786                                    == menu.initial_position.to_offset(&snapshot)
 5787                            };
 5788                        if position_matches {
 5789                            // Preserve markdown cache before `set_filter_results` because it will
 5790                            // try to populate the documentation cache.
 5791                            menu.preserve_markdown_cache(prev_menu);
 5792                        }
 5793                    };
 5794
 5795                    menu.set_filter_results(matches, provider, window, cx);
 5796                }) else {
 5797                    return;
 5798                };
 5799
 5800                menu.visible().then_some(menu)
 5801            };
 5802
 5803            editor
 5804                .update_in(cx, |editor, window, cx| {
 5805                    if editor.focus_handle.is_focused(window)
 5806                        && let Some(menu) = menu
 5807                    {
 5808                        *editor.context_menu.borrow_mut() =
 5809                            Some(CodeContextMenu::Completions(menu));
 5810
 5811                        crate::hover_popover::hide_hover(editor, cx);
 5812                        if editor.show_edit_predictions_in_menu() {
 5813                            editor.update_visible_edit_prediction(window, cx);
 5814                        } else {
 5815                            editor.discard_edit_prediction(false, cx);
 5816                        }
 5817
 5818                        cx.notify();
 5819                        return;
 5820                    }
 5821
 5822                    if editor.completion_tasks.len() <= 1 {
 5823                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5824                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5825                        // If it was already hidden and we don't show edit predictions in the menu,
 5826                        // we should also show the edit prediction when available.
 5827                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5828                            editor.update_visible_edit_prediction(window, cx);
 5829                        }
 5830                    }
 5831                })
 5832                .ok();
 5833        });
 5834
 5835        self.completion_tasks.push((id, task));
 5836    }
 5837
 5838    #[cfg(feature = "test-support")]
 5839    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5840        let menu = self.context_menu.borrow();
 5841        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5842            let completions = menu.completions.borrow();
 5843            Some(completions.to_vec())
 5844        } else {
 5845            None
 5846        }
 5847    }
 5848
 5849    pub fn with_completions_menu_matching_id<R>(
 5850        &self,
 5851        id: CompletionId,
 5852        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5853    ) -> R {
 5854        let mut context_menu = self.context_menu.borrow_mut();
 5855        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5856            return f(None);
 5857        };
 5858        if completions_menu.id != id {
 5859            return f(None);
 5860        }
 5861        f(Some(completions_menu))
 5862    }
 5863
 5864    pub fn confirm_completion(
 5865        &mut self,
 5866        action: &ConfirmCompletion,
 5867        window: &mut Window,
 5868        cx: &mut Context<Self>,
 5869    ) -> Option<Task<Result<()>>> {
 5870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5871        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5872    }
 5873
 5874    pub fn confirm_completion_insert(
 5875        &mut self,
 5876        _: &ConfirmCompletionInsert,
 5877        window: &mut Window,
 5878        cx: &mut Context<Self>,
 5879    ) -> Option<Task<Result<()>>> {
 5880        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5881        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5882    }
 5883
 5884    pub fn confirm_completion_replace(
 5885        &mut self,
 5886        _: &ConfirmCompletionReplace,
 5887        window: &mut Window,
 5888        cx: &mut Context<Self>,
 5889    ) -> Option<Task<Result<()>>> {
 5890        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5891        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5892    }
 5893
 5894    pub fn compose_completion(
 5895        &mut self,
 5896        action: &ComposeCompletion,
 5897        window: &mut Window,
 5898        cx: &mut Context<Self>,
 5899    ) -> Option<Task<Result<()>>> {
 5900        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5901        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5902    }
 5903
 5904    fn do_completion(
 5905        &mut self,
 5906        item_ix: Option<usize>,
 5907        intent: CompletionIntent,
 5908        window: &mut Window,
 5909        cx: &mut Context<Editor>,
 5910    ) -> Option<Task<Result<()>>> {
 5911        use language::ToOffset as _;
 5912
 5913        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5914        else {
 5915            return None;
 5916        };
 5917
 5918        let candidate_id = {
 5919            let entries = completions_menu.entries.borrow();
 5920            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5921            if self.show_edit_predictions_in_menu() {
 5922                self.discard_edit_prediction(true, cx);
 5923            }
 5924            mat.candidate_id
 5925        };
 5926
 5927        let completion = completions_menu
 5928            .completions
 5929            .borrow()
 5930            .get(candidate_id)?
 5931            .clone();
 5932        cx.stop_propagation();
 5933
 5934        let buffer_handle = completions_menu.buffer.clone();
 5935
 5936        let CompletionEdit {
 5937            new_text,
 5938            snippet,
 5939            replace_range,
 5940        } = process_completion_for_edit(
 5941            &completion,
 5942            intent,
 5943            &buffer_handle,
 5944            &completions_menu.initial_position.text_anchor,
 5945            cx,
 5946        );
 5947
 5948        let buffer = buffer_handle.read(cx);
 5949        let snapshot = self.buffer.read(cx).snapshot(cx);
 5950        let newest_anchor = self.selections.newest_anchor();
 5951        let replace_range_multibuffer = {
 5952            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5953            let multibuffer_anchor = snapshot
 5954                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5955                .unwrap()
 5956                ..snapshot
 5957                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5958                    .unwrap();
 5959            multibuffer_anchor.start.to_offset(&snapshot)
 5960                ..multibuffer_anchor.end.to_offset(&snapshot)
 5961        };
 5962        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5963            return None;
 5964        }
 5965
 5966        let old_text = buffer
 5967            .text_for_range(replace_range.clone())
 5968            .collect::<String>();
 5969        let lookbehind = newest_anchor
 5970            .start
 5971            .text_anchor
 5972            .to_offset(buffer)
 5973            .saturating_sub(replace_range.start);
 5974        let lookahead = replace_range
 5975            .end
 5976            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5977        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5978        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5979
 5980        let selections = self.selections.all::<usize>(cx);
 5981        let mut ranges = Vec::new();
 5982        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5983
 5984        for selection in &selections {
 5985            let range = if selection.id == newest_anchor.id {
 5986                replace_range_multibuffer.clone()
 5987            } else {
 5988                let mut range = selection.range();
 5989
 5990                // if prefix is present, don't duplicate it
 5991                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5992                    range.start = range.start.saturating_sub(lookbehind);
 5993
 5994                    // if suffix is also present, mimic the newest cursor and replace it
 5995                    if selection.id != newest_anchor.id
 5996                        && snapshot.contains_str_at(range.end, suffix)
 5997                    {
 5998                        range.end += lookahead;
 5999                    }
 6000                }
 6001                range
 6002            };
 6003
 6004            ranges.push(range.clone());
 6005
 6006            if !self.linked_edit_ranges.is_empty() {
 6007                let start_anchor = snapshot.anchor_before(range.start);
 6008                let end_anchor = snapshot.anchor_after(range.end);
 6009                if let Some(ranges) = self
 6010                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6011                {
 6012                    for (buffer, edits) in ranges {
 6013                        linked_edits
 6014                            .entry(buffer.clone())
 6015                            .or_default()
 6016                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6017                    }
 6018                }
 6019            }
 6020        }
 6021
 6022        let common_prefix_len = old_text
 6023            .chars()
 6024            .zip(new_text.chars())
 6025            .take_while(|(a, b)| a == b)
 6026            .map(|(a, _)| a.len_utf8())
 6027            .sum::<usize>();
 6028
 6029        cx.emit(EditorEvent::InputHandled {
 6030            utf16_range_to_replace: None,
 6031            text: new_text[common_prefix_len..].into(),
 6032        });
 6033
 6034        self.transact(window, cx, |editor, window, cx| {
 6035            if let Some(mut snippet) = snippet {
 6036                snippet.text = new_text.to_string();
 6037                editor
 6038                    .insert_snippet(&ranges, snippet, window, cx)
 6039                    .log_err();
 6040            } else {
 6041                editor.buffer.update(cx, |multi_buffer, cx| {
 6042                    let auto_indent = match completion.insert_text_mode {
 6043                        Some(InsertTextMode::AS_IS) => None,
 6044                        _ => editor.autoindent_mode.clone(),
 6045                    };
 6046                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6047                    multi_buffer.edit(edits, auto_indent, cx);
 6048                });
 6049            }
 6050            for (buffer, edits) in linked_edits {
 6051                buffer.update(cx, |buffer, cx| {
 6052                    let snapshot = buffer.snapshot();
 6053                    let edits = edits
 6054                        .into_iter()
 6055                        .map(|(range, text)| {
 6056                            use text::ToPoint as TP;
 6057                            let end_point = TP::to_point(&range.end, &snapshot);
 6058                            let start_point = TP::to_point(&range.start, &snapshot);
 6059                            (start_point..end_point, text)
 6060                        })
 6061                        .sorted_by_key(|(range, _)| range.start);
 6062                    buffer.edit(edits, None, cx);
 6063                })
 6064            }
 6065
 6066            editor.refresh_edit_prediction(true, false, window, cx);
 6067        });
 6068        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 6069
 6070        let show_new_completions_on_confirm = completion
 6071            .confirm
 6072            .as_ref()
 6073            .is_some_and(|confirm| confirm(intent, window, cx));
 6074        if show_new_completions_on_confirm {
 6075            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6076        }
 6077
 6078        let provider = self.completion_provider.as_ref()?;
 6079        drop(completion);
 6080        let apply_edits = provider.apply_additional_edits_for_completion(
 6081            buffer_handle,
 6082            completions_menu.completions.clone(),
 6083            candidate_id,
 6084            true,
 6085            cx,
 6086        );
 6087
 6088        let editor_settings = EditorSettings::get_global(cx);
 6089        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6090            // After the code completion is finished, users often want to know what signatures are needed.
 6091            // so we should automatically call signature_help
 6092            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6093        }
 6094
 6095        Some(cx.foreground_executor().spawn(async move {
 6096            apply_edits.await?;
 6097            Ok(())
 6098        }))
 6099    }
 6100
 6101    pub fn toggle_code_actions(
 6102        &mut self,
 6103        action: &ToggleCodeActions,
 6104        window: &mut Window,
 6105        cx: &mut Context<Self>,
 6106    ) {
 6107        let quick_launch = action.quick_launch;
 6108        let mut context_menu = self.context_menu.borrow_mut();
 6109        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6110            if code_actions.deployed_from == action.deployed_from {
 6111                // Toggle if we're selecting the same one
 6112                *context_menu = None;
 6113                cx.notify();
 6114                return;
 6115            } else {
 6116                // Otherwise, clear it and start a new one
 6117                *context_menu = None;
 6118                cx.notify();
 6119            }
 6120        }
 6121        drop(context_menu);
 6122        let snapshot = self.snapshot(window, cx);
 6123        let deployed_from = action.deployed_from.clone();
 6124        let action = action.clone();
 6125        self.completion_tasks.clear();
 6126        self.discard_edit_prediction(false, cx);
 6127
 6128        let multibuffer_point = match &action.deployed_from {
 6129            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6130                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6131            }
 6132            _ => self.selections.newest::<Point>(cx).head(),
 6133        };
 6134        let Some((buffer, buffer_row)) = snapshot
 6135            .buffer_snapshot
 6136            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6137            .and_then(|(buffer_snapshot, range)| {
 6138                self.buffer()
 6139                    .read(cx)
 6140                    .buffer(buffer_snapshot.remote_id())
 6141                    .map(|buffer| (buffer, range.start.row))
 6142            })
 6143        else {
 6144            return;
 6145        };
 6146        let buffer_id = buffer.read(cx).remote_id();
 6147        let tasks = self
 6148            .tasks
 6149            .get(&(buffer_id, buffer_row))
 6150            .map(|t| Arc::new(t.to_owned()));
 6151
 6152        if !self.focus_handle.is_focused(window) {
 6153            return;
 6154        }
 6155        let project = self.project.clone();
 6156
 6157        let code_actions_task = match deployed_from {
 6158            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6159            _ => self.code_actions(buffer_row, window, cx),
 6160        };
 6161
 6162        let runnable_task = match deployed_from {
 6163            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6164            _ => {
 6165                let mut task_context_task = Task::ready(None);
 6166                if let Some(tasks) = &tasks
 6167                    && let Some(project) = project
 6168                {
 6169                    task_context_task =
 6170                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6171                }
 6172
 6173                cx.spawn_in(window, {
 6174                    let buffer = buffer.clone();
 6175                    async move |editor, cx| {
 6176                        let task_context = task_context_task.await;
 6177
 6178                        let resolved_tasks =
 6179                            tasks
 6180                                .zip(task_context.clone())
 6181                                .map(|(tasks, task_context)| ResolvedTasks {
 6182                                    templates: tasks.resolve(&task_context).collect(),
 6183                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6184                                        multibuffer_point.row,
 6185                                        tasks.column,
 6186                                    )),
 6187                                });
 6188                        let debug_scenarios = editor
 6189                            .update(cx, |editor, cx| {
 6190                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6191                            })?
 6192                            .await;
 6193                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6194                    }
 6195                })
 6196            }
 6197        };
 6198
 6199        cx.spawn_in(window, async move |editor, cx| {
 6200            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6201            let code_actions = code_actions_task.await;
 6202            let spawn_straight_away = quick_launch
 6203                && resolved_tasks
 6204                    .as_ref()
 6205                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6206                && code_actions
 6207                    .as_ref()
 6208                    .is_none_or(|actions| actions.is_empty())
 6209                && debug_scenarios.is_empty();
 6210
 6211            editor.update_in(cx, |editor, window, cx| {
 6212                crate::hover_popover::hide_hover(editor, cx);
 6213                let actions = CodeActionContents::new(
 6214                    resolved_tasks,
 6215                    code_actions,
 6216                    debug_scenarios,
 6217                    task_context.unwrap_or_default(),
 6218                );
 6219
 6220                // Don't show the menu if there are no actions available
 6221                if actions.is_empty() {
 6222                    cx.notify();
 6223                    return Task::ready(Ok(()));
 6224                }
 6225
 6226                *editor.context_menu.borrow_mut() =
 6227                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6228                        buffer,
 6229                        actions,
 6230                        selected_item: Default::default(),
 6231                        scroll_handle: UniformListScrollHandle::default(),
 6232                        deployed_from,
 6233                    }));
 6234                cx.notify();
 6235                if spawn_straight_away
 6236                    && let Some(task) = editor.confirm_code_action(
 6237                        &ConfirmCodeAction { item_ix: Some(0) },
 6238                        window,
 6239                        cx,
 6240                    )
 6241                {
 6242                    return task;
 6243                }
 6244
 6245                Task::ready(Ok(()))
 6246            })
 6247        })
 6248        .detach_and_log_err(cx);
 6249    }
 6250
 6251    fn debug_scenarios(
 6252        &mut self,
 6253        resolved_tasks: &Option<ResolvedTasks>,
 6254        buffer: &Entity<Buffer>,
 6255        cx: &mut App,
 6256    ) -> Task<Vec<task::DebugScenario>> {
 6257        maybe!({
 6258            let project = self.project()?;
 6259            let dap_store = project.read(cx).dap_store();
 6260            let mut scenarios = vec![];
 6261            let resolved_tasks = resolved_tasks.as_ref()?;
 6262            let buffer = buffer.read(cx);
 6263            let language = buffer.language()?;
 6264            let file = buffer.file();
 6265            let debug_adapter = language_settings(language.name().into(), file, cx)
 6266                .debuggers
 6267                .first()
 6268                .map(SharedString::from)
 6269                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6270
 6271            dap_store.update(cx, |dap_store, cx| {
 6272                for (_, task) in &resolved_tasks.templates {
 6273                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6274                        task.original_task().clone(),
 6275                        debug_adapter.clone().into(),
 6276                        task.display_label().to_owned().into(),
 6277                        cx,
 6278                    );
 6279                    scenarios.push(maybe_scenario);
 6280                }
 6281            });
 6282            Some(cx.background_spawn(async move {
 6283                futures::future::join_all(scenarios)
 6284                    .await
 6285                    .into_iter()
 6286                    .flatten()
 6287                    .collect::<Vec<_>>()
 6288            }))
 6289        })
 6290        .unwrap_or_else(|| Task::ready(vec![]))
 6291    }
 6292
 6293    fn code_actions(
 6294        &mut self,
 6295        buffer_row: u32,
 6296        window: &mut Window,
 6297        cx: &mut Context<Self>,
 6298    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6299        let mut task = self.code_actions_task.take();
 6300        cx.spawn_in(window, async move |editor, cx| {
 6301            while let Some(prev_task) = task {
 6302                prev_task.await.log_err();
 6303                task = editor
 6304                    .update(cx, |this, _| this.code_actions_task.take())
 6305                    .ok()?;
 6306            }
 6307
 6308            editor
 6309                .update(cx, |editor, cx| {
 6310                    editor
 6311                        .available_code_actions
 6312                        .clone()
 6313                        .and_then(|(location, code_actions)| {
 6314                            let snapshot = location.buffer.read(cx).snapshot();
 6315                            let point_range = location.range.to_point(&snapshot);
 6316                            let point_range = point_range.start.row..=point_range.end.row;
 6317                            if point_range.contains(&buffer_row) {
 6318                                Some(code_actions)
 6319                            } else {
 6320                                None
 6321                            }
 6322                        })
 6323                })
 6324                .ok()
 6325                .flatten()
 6326        })
 6327    }
 6328
 6329    pub fn confirm_code_action(
 6330        &mut self,
 6331        action: &ConfirmCodeAction,
 6332        window: &mut Window,
 6333        cx: &mut Context<Self>,
 6334    ) -> Option<Task<Result<()>>> {
 6335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6336
 6337        let actions_menu =
 6338            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6339                menu
 6340            } else {
 6341                return None;
 6342            };
 6343
 6344        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6345        let action = actions_menu.actions.get(action_ix)?;
 6346        let title = action.label();
 6347        let buffer = actions_menu.buffer;
 6348        let workspace = self.workspace()?;
 6349
 6350        match action {
 6351            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6352                workspace.update(cx, |workspace, cx| {
 6353                    workspace.schedule_resolved_task(
 6354                        task_source_kind,
 6355                        resolved_task,
 6356                        false,
 6357                        window,
 6358                        cx,
 6359                    );
 6360
 6361                    Some(Task::ready(Ok(())))
 6362                })
 6363            }
 6364            CodeActionsItem::CodeAction {
 6365                excerpt_id,
 6366                action,
 6367                provider,
 6368            } => {
 6369                let apply_code_action =
 6370                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6371                let workspace = workspace.downgrade();
 6372                Some(cx.spawn_in(window, async move |editor, cx| {
 6373                    let project_transaction = apply_code_action.await?;
 6374                    Self::open_project_transaction(
 6375                        &editor,
 6376                        workspace,
 6377                        project_transaction,
 6378                        title,
 6379                        cx,
 6380                    )
 6381                    .await
 6382                }))
 6383            }
 6384            CodeActionsItem::DebugScenario(scenario) => {
 6385                let context = actions_menu.actions.context;
 6386
 6387                workspace.update(cx, |workspace, cx| {
 6388                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6389                    workspace.start_debug_session(
 6390                        scenario,
 6391                        context,
 6392                        Some(buffer),
 6393                        None,
 6394                        window,
 6395                        cx,
 6396                    );
 6397                });
 6398                Some(Task::ready(Ok(())))
 6399            }
 6400        }
 6401    }
 6402
 6403    pub async fn open_project_transaction(
 6404        editor: &WeakEntity<Editor>,
 6405        workspace: WeakEntity<Workspace>,
 6406        transaction: ProjectTransaction,
 6407        title: String,
 6408        cx: &mut AsyncWindowContext,
 6409    ) -> Result<()> {
 6410        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6411        cx.update(|_, cx| {
 6412            entries.sort_unstable_by_key(|(buffer, _)| {
 6413                buffer.read(cx).file().map(|f| f.path().clone())
 6414            });
 6415        })?;
 6416
 6417        // If the project transaction's edits are all contained within this editor, then
 6418        // avoid opening a new editor to display them.
 6419
 6420        if let Some((buffer, transaction)) = entries.first() {
 6421            if entries.len() == 1 {
 6422                let excerpt = editor.update(cx, |editor, cx| {
 6423                    editor
 6424                        .buffer()
 6425                        .read(cx)
 6426                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6427                })?;
 6428                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6429                    && excerpted_buffer == *buffer
 6430                {
 6431                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6432                        let excerpt_range = excerpt_range.to_offset(buffer);
 6433                        buffer
 6434                            .edited_ranges_for_transaction::<usize>(transaction)
 6435                            .all(|range| {
 6436                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6437                            })
 6438                    })?;
 6439
 6440                    if all_edits_within_excerpt {
 6441                        return Ok(());
 6442                    }
 6443                }
 6444            }
 6445        } else {
 6446            return Ok(());
 6447        }
 6448
 6449        let mut ranges_to_highlight = Vec::new();
 6450        let excerpt_buffer = cx.new(|cx| {
 6451            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6452            for (buffer_handle, transaction) in &entries {
 6453                let edited_ranges = buffer_handle
 6454                    .read(cx)
 6455                    .edited_ranges_for_transaction::<Point>(transaction)
 6456                    .collect::<Vec<_>>();
 6457                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6458                    PathKey::for_buffer(buffer_handle, cx),
 6459                    buffer_handle.clone(),
 6460                    edited_ranges,
 6461                    multibuffer_context_lines(cx),
 6462                    cx,
 6463                );
 6464
 6465                ranges_to_highlight.extend(ranges);
 6466            }
 6467            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6468            multibuffer
 6469        })?;
 6470
 6471        workspace.update_in(cx, |workspace, window, cx| {
 6472            let project = workspace.project().clone();
 6473            let editor =
 6474                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6475            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6476            editor.update(cx, |editor, cx| {
 6477                editor.highlight_background::<Self>(
 6478                    &ranges_to_highlight,
 6479                    |theme| theme.colors().editor_highlighted_line_background,
 6480                    cx,
 6481                );
 6482            });
 6483        })?;
 6484
 6485        Ok(())
 6486    }
 6487
 6488    pub fn clear_code_action_providers(&mut self) {
 6489        self.code_action_providers.clear();
 6490        self.available_code_actions.take();
 6491    }
 6492
 6493    pub fn add_code_action_provider(
 6494        &mut self,
 6495        provider: Rc<dyn CodeActionProvider>,
 6496        window: &mut Window,
 6497        cx: &mut Context<Self>,
 6498    ) {
 6499        if self
 6500            .code_action_providers
 6501            .iter()
 6502            .any(|existing_provider| existing_provider.id() == provider.id())
 6503        {
 6504            return;
 6505        }
 6506
 6507        self.code_action_providers.push(provider);
 6508        self.refresh_code_actions(window, cx);
 6509    }
 6510
 6511    pub fn remove_code_action_provider(
 6512        &mut self,
 6513        id: Arc<str>,
 6514        window: &mut Window,
 6515        cx: &mut Context<Self>,
 6516    ) {
 6517        self.code_action_providers
 6518            .retain(|provider| provider.id() != id);
 6519        self.refresh_code_actions(window, cx);
 6520    }
 6521
 6522    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6523        !self.code_action_providers.is_empty()
 6524            && EditorSettings::get_global(cx).toolbar.code_actions
 6525    }
 6526
 6527    pub fn has_available_code_actions(&self) -> bool {
 6528        self.available_code_actions
 6529            .as_ref()
 6530            .is_some_and(|(_, actions)| !actions.is_empty())
 6531    }
 6532
 6533    fn render_inline_code_actions(
 6534        &self,
 6535        icon_size: ui::IconSize,
 6536        display_row: DisplayRow,
 6537        is_active: bool,
 6538        cx: &mut Context<Self>,
 6539    ) -> AnyElement {
 6540        let show_tooltip = !self.context_menu_visible();
 6541        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6542            .icon_size(icon_size)
 6543            .shape(ui::IconButtonShape::Square)
 6544            .icon_color(ui::Color::Hidden)
 6545            .toggle_state(is_active)
 6546            .when(show_tooltip, |this| {
 6547                this.tooltip({
 6548                    let focus_handle = self.focus_handle.clone();
 6549                    move |window, cx| {
 6550                        Tooltip::for_action_in(
 6551                            "Toggle Code Actions",
 6552                            &ToggleCodeActions {
 6553                                deployed_from: None,
 6554                                quick_launch: false,
 6555                            },
 6556                            &focus_handle,
 6557                            window,
 6558                            cx,
 6559                        )
 6560                    }
 6561                })
 6562            })
 6563            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6564                window.focus(&editor.focus_handle(cx));
 6565                editor.toggle_code_actions(
 6566                    &crate::actions::ToggleCodeActions {
 6567                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6568                            display_row,
 6569                        )),
 6570                        quick_launch: false,
 6571                    },
 6572                    window,
 6573                    cx,
 6574                );
 6575            }))
 6576            .into_any_element()
 6577    }
 6578
 6579    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6580        &self.context_menu
 6581    }
 6582
 6583    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6584        let newest_selection = self.selections.newest_anchor().clone();
 6585        let newest_selection_adjusted = self.selections.newest_adjusted(cx);
 6586        let buffer = self.buffer.read(cx);
 6587        if newest_selection.head().diff_base_anchor.is_some() {
 6588            return None;
 6589        }
 6590        let (start_buffer, start) =
 6591            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6592        let (end_buffer, end) =
 6593            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6594        if start_buffer != end_buffer {
 6595            return None;
 6596        }
 6597
 6598        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6599            cx.background_executor()
 6600                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6601                .await;
 6602
 6603            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6604                let providers = this.code_action_providers.clone();
 6605                let tasks = this
 6606                    .code_action_providers
 6607                    .iter()
 6608                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6609                    .collect::<Vec<_>>();
 6610                (providers, tasks)
 6611            })?;
 6612
 6613            let mut actions = Vec::new();
 6614            for (provider, provider_actions) in
 6615                providers.into_iter().zip(future::join_all(tasks).await)
 6616            {
 6617                if let Some(provider_actions) = provider_actions.log_err() {
 6618                    actions.extend(provider_actions.into_iter().map(|action| {
 6619                        AvailableCodeAction {
 6620                            excerpt_id: newest_selection.start.excerpt_id,
 6621                            action,
 6622                            provider: provider.clone(),
 6623                        }
 6624                    }));
 6625                }
 6626            }
 6627
 6628            this.update(cx, |this, cx| {
 6629                this.available_code_actions = if actions.is_empty() {
 6630                    None
 6631                } else {
 6632                    Some((
 6633                        Location {
 6634                            buffer: start_buffer,
 6635                            range: start..end,
 6636                        },
 6637                        actions.into(),
 6638                    ))
 6639                };
 6640                cx.notify();
 6641            })
 6642        }));
 6643        None
 6644    }
 6645
 6646    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6647        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6648            self.show_git_blame_inline = false;
 6649
 6650            self.show_git_blame_inline_delay_task =
 6651                Some(cx.spawn_in(window, async move |this, cx| {
 6652                    cx.background_executor().timer(delay).await;
 6653
 6654                    this.update(cx, |this, cx| {
 6655                        this.show_git_blame_inline = true;
 6656                        cx.notify();
 6657                    })
 6658                    .log_err();
 6659                }));
 6660        }
 6661    }
 6662
 6663    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6664        let snapshot = self.snapshot(window, cx);
 6665        let cursor = self.selections.newest::<Point>(cx).head();
 6666        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6667        else {
 6668            return;
 6669        };
 6670
 6671        let Some(blame) = self.blame.as_ref() else {
 6672            return;
 6673        };
 6674
 6675        let row_info = RowInfo {
 6676            buffer_id: Some(buffer.remote_id()),
 6677            buffer_row: Some(point.row),
 6678            ..Default::default()
 6679        };
 6680        let Some((buffer, blame_entry)) = blame
 6681            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6682            .flatten()
 6683        else {
 6684            return;
 6685        };
 6686
 6687        let anchor = self.selections.newest_anchor().head();
 6688        let position = self.to_pixel_point(anchor, &snapshot, window);
 6689        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6690            self.show_blame_popover(
 6691                buffer,
 6692                &blame_entry,
 6693                position + last_bounds.origin,
 6694                true,
 6695                cx,
 6696            );
 6697        };
 6698    }
 6699
 6700    fn show_blame_popover(
 6701        &mut self,
 6702        buffer: BufferId,
 6703        blame_entry: &BlameEntry,
 6704        position: gpui::Point<Pixels>,
 6705        ignore_timeout: bool,
 6706        cx: &mut Context<Self>,
 6707    ) {
 6708        if let Some(state) = &mut self.inline_blame_popover {
 6709            state.hide_task.take();
 6710        } else {
 6711            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6712            let blame_entry = blame_entry.clone();
 6713            let show_task = cx.spawn(async move |editor, cx| {
 6714                if !ignore_timeout {
 6715                    cx.background_executor()
 6716                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6717                        .await;
 6718                }
 6719                editor
 6720                    .update(cx, |editor, cx| {
 6721                        editor.inline_blame_popover_show_task.take();
 6722                        let Some(blame) = editor.blame.as_ref() else {
 6723                            return;
 6724                        };
 6725                        let blame = blame.read(cx);
 6726                        let details = blame.details_for_entry(buffer, &blame_entry);
 6727                        let markdown = cx.new(|cx| {
 6728                            Markdown::new(
 6729                                details
 6730                                    .as_ref()
 6731                                    .map(|message| message.message.clone())
 6732                                    .unwrap_or_default(),
 6733                                None,
 6734                                None,
 6735                                cx,
 6736                            )
 6737                        });
 6738                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6739                            position,
 6740                            hide_task: None,
 6741                            popover_bounds: None,
 6742                            popover_state: InlineBlamePopoverState {
 6743                                scroll_handle: ScrollHandle::new(),
 6744                                commit_message: details,
 6745                                markdown,
 6746                            },
 6747                            keyboard_grace: ignore_timeout,
 6748                        });
 6749                        cx.notify();
 6750                    })
 6751                    .ok();
 6752            });
 6753            self.inline_blame_popover_show_task = Some(show_task);
 6754        }
 6755    }
 6756
 6757    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6758        self.inline_blame_popover_show_task.take();
 6759        if let Some(state) = &mut self.inline_blame_popover {
 6760            let hide_task = cx.spawn(async move |editor, cx| {
 6761                cx.background_executor()
 6762                    .timer(std::time::Duration::from_millis(100))
 6763                    .await;
 6764                editor
 6765                    .update(cx, |editor, cx| {
 6766                        editor.inline_blame_popover.take();
 6767                        cx.notify();
 6768                    })
 6769                    .ok();
 6770            });
 6771            state.hide_task = Some(hide_task);
 6772        }
 6773    }
 6774
 6775    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6776        if self.pending_rename.is_some() {
 6777            return None;
 6778        }
 6779
 6780        let provider = self.semantics_provider.clone()?;
 6781        let buffer = self.buffer.read(cx);
 6782        let newest_selection = self.selections.newest_anchor().clone();
 6783        let cursor_position = newest_selection.head();
 6784        let (cursor_buffer, cursor_buffer_position) =
 6785            buffer.text_anchor_for_position(cursor_position, cx)?;
 6786        let (tail_buffer, tail_buffer_position) =
 6787            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6788        if cursor_buffer != tail_buffer {
 6789            return None;
 6790        }
 6791
 6792        let snapshot = cursor_buffer.read(cx).snapshot();
 6793        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6794        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6795        if start_word_range != end_word_range {
 6796            self.document_highlights_task.take();
 6797            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6798            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6799            return None;
 6800        }
 6801
 6802        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6803        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6804            cx.background_executor()
 6805                .timer(Duration::from_millis(debounce))
 6806                .await;
 6807
 6808            let highlights = if let Some(highlights) = cx
 6809                .update(|cx| {
 6810                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6811                })
 6812                .ok()
 6813                .flatten()
 6814            {
 6815                highlights.await.log_err()
 6816            } else {
 6817                None
 6818            };
 6819
 6820            if let Some(highlights) = highlights {
 6821                this.update(cx, |this, cx| {
 6822                    if this.pending_rename.is_some() {
 6823                        return;
 6824                    }
 6825
 6826                    let buffer = this.buffer.read(cx);
 6827                    if buffer
 6828                        .text_anchor_for_position(cursor_position, cx)
 6829                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6830                    {
 6831                        return;
 6832                    }
 6833
 6834                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6835                    let mut write_ranges = Vec::new();
 6836                    let mut read_ranges = Vec::new();
 6837                    for highlight in highlights {
 6838                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6839                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6840                        {
 6841                            let start = highlight
 6842                                .range
 6843                                .start
 6844                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6845                            let end = highlight
 6846                                .range
 6847                                .end
 6848                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6849                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6850                                continue;
 6851                            }
 6852
 6853                            let range = Anchor {
 6854                                buffer_id: Some(buffer_id),
 6855                                excerpt_id,
 6856                                text_anchor: start,
 6857                                diff_base_anchor: None,
 6858                            }..Anchor {
 6859                                buffer_id: Some(buffer_id),
 6860                                excerpt_id,
 6861                                text_anchor: end,
 6862                                diff_base_anchor: None,
 6863                            };
 6864                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6865                                write_ranges.push(range);
 6866                            } else {
 6867                                read_ranges.push(range);
 6868                            }
 6869                        }
 6870                    }
 6871
 6872                    this.highlight_background::<DocumentHighlightRead>(
 6873                        &read_ranges,
 6874                        |theme| theme.colors().editor_document_highlight_read_background,
 6875                        cx,
 6876                    );
 6877                    this.highlight_background::<DocumentHighlightWrite>(
 6878                        &write_ranges,
 6879                        |theme| theme.colors().editor_document_highlight_write_background,
 6880                        cx,
 6881                    );
 6882                    cx.notify();
 6883                })
 6884                .log_err();
 6885            }
 6886        }));
 6887        None
 6888    }
 6889
 6890    fn prepare_highlight_query_from_selection(
 6891        &mut self,
 6892        cx: &mut Context<Editor>,
 6893    ) -> Option<(String, Range<Anchor>)> {
 6894        if matches!(self.mode, EditorMode::SingleLine) {
 6895            return None;
 6896        }
 6897        if !EditorSettings::get_global(cx).selection_highlight {
 6898            return None;
 6899        }
 6900        if self.selections.count() != 1 || self.selections.line_mode {
 6901            return None;
 6902        }
 6903        let selection = self.selections.newest::<Point>(cx);
 6904        if selection.is_empty() || selection.start.row != selection.end.row {
 6905            return None;
 6906        }
 6907        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6908        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6909        let query = multi_buffer_snapshot
 6910            .text_for_range(selection_anchor_range.clone())
 6911            .collect::<String>();
 6912        if query.trim().is_empty() {
 6913            return None;
 6914        }
 6915        Some((query, selection_anchor_range))
 6916    }
 6917
 6918    fn update_selection_occurrence_highlights(
 6919        &mut self,
 6920        query_text: String,
 6921        query_range: Range<Anchor>,
 6922        multi_buffer_range_to_query: Range<Point>,
 6923        use_debounce: bool,
 6924        window: &mut Window,
 6925        cx: &mut Context<Editor>,
 6926    ) -> Task<()> {
 6927        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6928        cx.spawn_in(window, async move |editor, cx| {
 6929            if use_debounce {
 6930                cx.background_executor()
 6931                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6932                    .await;
 6933            }
 6934            let match_task = cx.background_spawn(async move {
 6935                let buffer_ranges = multi_buffer_snapshot
 6936                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6937                    .into_iter()
 6938                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6939                let mut match_ranges = Vec::new();
 6940                let Ok(regex) = project::search::SearchQuery::text(
 6941                    query_text.clone(),
 6942                    false,
 6943                    false,
 6944                    false,
 6945                    Default::default(),
 6946                    Default::default(),
 6947                    false,
 6948                    None,
 6949                ) else {
 6950                    return Vec::default();
 6951                };
 6952                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6953                    match_ranges.extend(
 6954                        regex
 6955                            .search(buffer_snapshot, Some(search_range.clone()))
 6956                            .await
 6957                            .into_iter()
 6958                            .filter_map(|match_range| {
 6959                                let match_start = buffer_snapshot
 6960                                    .anchor_after(search_range.start + match_range.start);
 6961                                let match_end = buffer_snapshot
 6962                                    .anchor_before(search_range.start + match_range.end);
 6963                                let match_anchor_range = Anchor::range_in_buffer(
 6964                                    excerpt_id,
 6965                                    buffer_snapshot.remote_id(),
 6966                                    match_start..match_end,
 6967                                );
 6968                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6969                            }),
 6970                    );
 6971                }
 6972                match_ranges
 6973            });
 6974            let match_ranges = match_task.await;
 6975            editor
 6976                .update_in(cx, |editor, _, cx| {
 6977                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6978                    if !match_ranges.is_empty() {
 6979                        editor.highlight_background::<SelectedTextHighlight>(
 6980                            &match_ranges,
 6981                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6982                            cx,
 6983                        )
 6984                    }
 6985                })
 6986                .log_err();
 6987        })
 6988    }
 6989
 6990    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6991        struct NewlineFold;
 6992        let type_id = std::any::TypeId::of::<NewlineFold>();
 6993        if !self.mode.is_single_line() {
 6994            return;
 6995        }
 6996        let snapshot = self.snapshot(window, cx);
 6997        if snapshot.buffer_snapshot.max_point().row == 0 {
 6998            return;
 6999        }
 7000        let task = cx.background_spawn(async move {
 7001            let new_newlines = snapshot
 7002                .buffer_chars_at(0)
 7003                .filter_map(|(c, i)| {
 7004                    if c == '\n' {
 7005                        Some(
 7006                            snapshot.buffer_snapshot.anchor_after(i)
 7007                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 7008                        )
 7009                    } else {
 7010                        None
 7011                    }
 7012                })
 7013                .collect::<Vec<_>>();
 7014            let existing_newlines = snapshot
 7015                .folds_in_range(0..snapshot.buffer_snapshot.len())
 7016                .filter_map(|fold| {
 7017                    if fold.placeholder.type_tag == Some(type_id) {
 7018                        Some(fold.range.start..fold.range.end)
 7019                    } else {
 7020                        None
 7021                    }
 7022                })
 7023                .collect::<Vec<_>>();
 7024
 7025            (new_newlines, existing_newlines)
 7026        });
 7027        self.folding_newlines = cx.spawn(async move |this, cx| {
 7028            let (new_newlines, existing_newlines) = task.await;
 7029            if new_newlines == existing_newlines {
 7030                return;
 7031            }
 7032            let placeholder = FoldPlaceholder {
 7033                render: Arc::new(move |_, _, cx| {
 7034                    div()
 7035                        .bg(cx.theme().status().hint_background)
 7036                        .border_b_1()
 7037                        .size_full()
 7038                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7039                        .border_color(cx.theme().status().hint)
 7040                        .child("\\n")
 7041                        .into_any()
 7042                }),
 7043                constrain_width: false,
 7044                merge_adjacent: false,
 7045                type_tag: Some(type_id),
 7046            };
 7047            let creases = new_newlines
 7048                .into_iter()
 7049                .map(|range| Crease::simple(range, placeholder.clone()))
 7050                .collect();
 7051            this.update(cx, |this, cx| {
 7052                this.display_map.update(cx, |display_map, cx| {
 7053                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7054                    display_map.fold(creases, cx);
 7055                });
 7056            })
 7057            .ok();
 7058        });
 7059    }
 7060
 7061    fn refresh_selected_text_highlights(
 7062        &mut self,
 7063        on_buffer_edit: bool,
 7064        window: &mut Window,
 7065        cx: &mut Context<Editor>,
 7066    ) {
 7067        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 7068        else {
 7069            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7070            self.quick_selection_highlight_task.take();
 7071            self.debounced_selection_highlight_task.take();
 7072            return;
 7073        };
 7074        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7075        if on_buffer_edit
 7076            || self
 7077                .quick_selection_highlight_task
 7078                .as_ref()
 7079                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7080        {
 7081            let multi_buffer_visible_start = self
 7082                .scroll_manager
 7083                .anchor()
 7084                .anchor
 7085                .to_point(&multi_buffer_snapshot);
 7086            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7087                multi_buffer_visible_start
 7088                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7089                Bias::Left,
 7090            );
 7091            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7092            self.quick_selection_highlight_task = Some((
 7093                query_range.clone(),
 7094                self.update_selection_occurrence_highlights(
 7095                    query_text.clone(),
 7096                    query_range.clone(),
 7097                    multi_buffer_visible_range,
 7098                    false,
 7099                    window,
 7100                    cx,
 7101                ),
 7102            ));
 7103        }
 7104        if on_buffer_edit
 7105            || self
 7106                .debounced_selection_highlight_task
 7107                .as_ref()
 7108                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7109        {
 7110            let multi_buffer_start = multi_buffer_snapshot
 7111                .anchor_before(0)
 7112                .to_point(&multi_buffer_snapshot);
 7113            let multi_buffer_end = multi_buffer_snapshot
 7114                .anchor_after(multi_buffer_snapshot.len())
 7115                .to_point(&multi_buffer_snapshot);
 7116            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7117            self.debounced_selection_highlight_task = Some((
 7118                query_range.clone(),
 7119                self.update_selection_occurrence_highlights(
 7120                    query_text,
 7121                    query_range,
 7122                    multi_buffer_full_range,
 7123                    true,
 7124                    window,
 7125                    cx,
 7126                ),
 7127            ));
 7128        }
 7129    }
 7130
 7131    pub fn refresh_edit_prediction(
 7132        &mut self,
 7133        debounce: bool,
 7134        user_requested: bool,
 7135        window: &mut Window,
 7136        cx: &mut Context<Self>,
 7137    ) -> Option<()> {
 7138        if DisableAiSettings::get_global(cx).disable_ai {
 7139            return None;
 7140        }
 7141
 7142        let provider = self.edit_prediction_provider()?;
 7143        let cursor = self.selections.newest_anchor().head();
 7144        let (buffer, cursor_buffer_position) =
 7145            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7146
 7147        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7148            self.discard_edit_prediction(false, cx);
 7149            return None;
 7150        }
 7151
 7152        self.update_visible_edit_prediction(window, cx);
 7153
 7154        if !user_requested
 7155            && (!self.should_show_edit_predictions()
 7156                || !self.is_focused(window)
 7157                || buffer.read(cx).is_empty())
 7158        {
 7159            self.discard_edit_prediction(false, cx);
 7160            return None;
 7161        }
 7162
 7163        provider.refresh(
 7164            self.project.clone(),
 7165            buffer,
 7166            cursor_buffer_position,
 7167            debounce,
 7168            cx,
 7169        );
 7170        Some(())
 7171    }
 7172
 7173    fn show_edit_predictions_in_menu(&self) -> bool {
 7174        match self.edit_prediction_settings {
 7175            EditPredictionSettings::Disabled => false,
 7176            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7177        }
 7178    }
 7179
 7180    pub fn edit_predictions_enabled(&self) -> bool {
 7181        match self.edit_prediction_settings {
 7182            EditPredictionSettings::Disabled => false,
 7183            EditPredictionSettings::Enabled { .. } => true,
 7184        }
 7185    }
 7186
 7187    fn edit_prediction_requires_modifier(&self) -> bool {
 7188        match self.edit_prediction_settings {
 7189            EditPredictionSettings::Disabled => false,
 7190            EditPredictionSettings::Enabled {
 7191                preview_requires_modifier,
 7192                ..
 7193            } => preview_requires_modifier,
 7194        }
 7195    }
 7196
 7197    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7198        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7199            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7200            self.discard_edit_prediction(false, cx);
 7201        } else {
 7202            let selection = self.selections.newest_anchor();
 7203            let cursor = selection.head();
 7204
 7205            if let Some((buffer, cursor_buffer_position)) =
 7206                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7207            {
 7208                self.edit_prediction_settings =
 7209                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7210            }
 7211        }
 7212    }
 7213
 7214    fn edit_prediction_settings_at_position(
 7215        &self,
 7216        buffer: &Entity<Buffer>,
 7217        buffer_position: language::Anchor,
 7218        cx: &App,
 7219    ) -> EditPredictionSettings {
 7220        if !self.mode.is_full()
 7221            || !self.show_edit_predictions_override.unwrap_or(true)
 7222            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7223        {
 7224            return EditPredictionSettings::Disabled;
 7225        }
 7226
 7227        let buffer = buffer.read(cx);
 7228
 7229        let file = buffer.file();
 7230
 7231        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7232            return EditPredictionSettings::Disabled;
 7233        };
 7234
 7235        let by_provider = matches!(
 7236            self.menu_edit_predictions_policy,
 7237            MenuEditPredictionsPolicy::ByProvider
 7238        );
 7239
 7240        let show_in_menu = by_provider
 7241            && self
 7242                .edit_prediction_provider
 7243                .as_ref()
 7244                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7245
 7246        let preview_requires_modifier =
 7247            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7248
 7249        EditPredictionSettings::Enabled {
 7250            show_in_menu,
 7251            preview_requires_modifier,
 7252        }
 7253    }
 7254
 7255    fn should_show_edit_predictions(&self) -> bool {
 7256        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7257    }
 7258
 7259    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7260        matches!(
 7261            self.edit_prediction_preview,
 7262            EditPredictionPreview::Active { .. }
 7263        )
 7264    }
 7265
 7266    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7267        let cursor = self.selections.newest_anchor().head();
 7268        if let Some((buffer, cursor_position)) =
 7269            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7270        {
 7271            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7272        } else {
 7273            false
 7274        }
 7275    }
 7276
 7277    pub fn supports_minimap(&self, cx: &App) -> bool {
 7278        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7279    }
 7280
 7281    fn edit_predictions_enabled_in_buffer(
 7282        &self,
 7283        buffer: &Entity<Buffer>,
 7284        buffer_position: language::Anchor,
 7285        cx: &App,
 7286    ) -> bool {
 7287        maybe!({
 7288            if self.read_only(cx) {
 7289                return Some(false);
 7290            }
 7291            let provider = self.edit_prediction_provider()?;
 7292            if !provider.is_enabled(buffer, buffer_position, cx) {
 7293                return Some(false);
 7294            }
 7295            let buffer = buffer.read(cx);
 7296            let Some(file) = buffer.file() else {
 7297                return Some(true);
 7298            };
 7299            let settings = all_language_settings(Some(file), cx);
 7300            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7301        })
 7302        .unwrap_or(false)
 7303    }
 7304
 7305    fn cycle_edit_prediction(
 7306        &mut self,
 7307        direction: Direction,
 7308        window: &mut Window,
 7309        cx: &mut Context<Self>,
 7310    ) -> Option<()> {
 7311        let provider = self.edit_prediction_provider()?;
 7312        let cursor = self.selections.newest_anchor().head();
 7313        let (buffer, cursor_buffer_position) =
 7314            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7315        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7316            return None;
 7317        }
 7318
 7319        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7320        self.update_visible_edit_prediction(window, cx);
 7321
 7322        Some(())
 7323    }
 7324
 7325    pub fn show_edit_prediction(
 7326        &mut self,
 7327        _: &ShowEditPrediction,
 7328        window: &mut Window,
 7329        cx: &mut Context<Self>,
 7330    ) {
 7331        if !self.has_active_edit_prediction() {
 7332            self.refresh_edit_prediction(false, true, window, cx);
 7333            return;
 7334        }
 7335
 7336        self.update_visible_edit_prediction(window, cx);
 7337    }
 7338
 7339    pub fn display_cursor_names(
 7340        &mut self,
 7341        _: &DisplayCursorNames,
 7342        window: &mut Window,
 7343        cx: &mut Context<Self>,
 7344    ) {
 7345        self.show_cursor_names(window, cx);
 7346    }
 7347
 7348    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7349        self.show_cursor_names = true;
 7350        cx.notify();
 7351        cx.spawn_in(window, async move |this, cx| {
 7352            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7353            this.update(cx, |this, cx| {
 7354                this.show_cursor_names = false;
 7355                cx.notify()
 7356            })
 7357            .ok()
 7358        })
 7359        .detach();
 7360    }
 7361
 7362    pub fn next_edit_prediction(
 7363        &mut self,
 7364        _: &NextEditPrediction,
 7365        window: &mut Window,
 7366        cx: &mut Context<Self>,
 7367    ) {
 7368        if self.has_active_edit_prediction() {
 7369            self.cycle_edit_prediction(Direction::Next, window, cx);
 7370        } else {
 7371            let is_copilot_disabled = self
 7372                .refresh_edit_prediction(false, true, window, cx)
 7373                .is_none();
 7374            if is_copilot_disabled {
 7375                cx.propagate();
 7376            }
 7377        }
 7378    }
 7379
 7380    pub fn previous_edit_prediction(
 7381        &mut self,
 7382        _: &PreviousEditPrediction,
 7383        window: &mut Window,
 7384        cx: &mut Context<Self>,
 7385    ) {
 7386        if self.has_active_edit_prediction() {
 7387            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7388        } else {
 7389            let is_copilot_disabled = self
 7390                .refresh_edit_prediction(false, true, window, cx)
 7391                .is_none();
 7392            if is_copilot_disabled {
 7393                cx.propagate();
 7394            }
 7395        }
 7396    }
 7397
 7398    pub fn accept_edit_prediction(
 7399        &mut self,
 7400        _: &AcceptEditPrediction,
 7401        window: &mut Window,
 7402        cx: &mut Context<Self>,
 7403    ) {
 7404        if self.show_edit_predictions_in_menu() {
 7405            self.hide_context_menu(window, cx);
 7406        }
 7407
 7408        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7409            return;
 7410        };
 7411
 7412        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7413
 7414        match &active_edit_prediction.completion {
 7415            EditPrediction::Move { target, .. } => {
 7416                let target = *target;
 7417
 7418                if let Some(position_map) = &self.last_position_map {
 7419                    if position_map
 7420                        .visible_row_range
 7421                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7422                        || !self.edit_prediction_requires_modifier()
 7423                    {
 7424                        self.unfold_ranges(&[target..target], true, false, cx);
 7425                        // Note that this is also done in vim's handler of the Tab action.
 7426                        self.change_selections(
 7427                            SelectionEffects::scroll(Autoscroll::newest()),
 7428                            window,
 7429                            cx,
 7430                            |selections| {
 7431                                selections.select_anchor_ranges([target..target]);
 7432                            },
 7433                        );
 7434                        self.clear_row_highlights::<EditPredictionPreview>();
 7435
 7436                        self.edit_prediction_preview
 7437                            .set_previous_scroll_position(None);
 7438                    } else {
 7439                        self.edit_prediction_preview
 7440                            .set_previous_scroll_position(Some(
 7441                                position_map.snapshot.scroll_anchor,
 7442                            ));
 7443
 7444                        self.highlight_rows::<EditPredictionPreview>(
 7445                            target..target,
 7446                            cx.theme().colors().editor_highlighted_line_background,
 7447                            RowHighlightOptions {
 7448                                autoscroll: true,
 7449                                ..Default::default()
 7450                            },
 7451                            cx,
 7452                        );
 7453                        self.request_autoscroll(Autoscroll::fit(), cx);
 7454                    }
 7455                }
 7456            }
 7457            EditPrediction::Edit { edits, .. } => {
 7458                if let Some(provider) = self.edit_prediction_provider() {
 7459                    provider.accept(cx);
 7460                }
 7461
 7462                // Store the transaction ID and selections before applying the edit
 7463                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7464
 7465                let snapshot = self.buffer.read(cx).snapshot(cx);
 7466                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7467
 7468                self.buffer.update(cx, |buffer, cx| {
 7469                    buffer.edit(edits.iter().cloned(), None, cx)
 7470                });
 7471
 7472                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7473                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7474                });
 7475
 7476                let selections = self.selections.disjoint_anchors();
 7477                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7478                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7479                    if has_new_transaction {
 7480                        self.selection_history
 7481                            .insert_transaction(transaction_id_now, selections);
 7482                    }
 7483                }
 7484
 7485                self.update_visible_edit_prediction(window, cx);
 7486                if self.active_edit_prediction.is_none() {
 7487                    self.refresh_edit_prediction(true, true, window, cx);
 7488                }
 7489
 7490                cx.notify();
 7491            }
 7492        }
 7493
 7494        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7495    }
 7496
 7497    pub fn accept_partial_edit_prediction(
 7498        &mut self,
 7499        _: &AcceptPartialEditPrediction,
 7500        window: &mut Window,
 7501        cx: &mut Context<Self>,
 7502    ) {
 7503        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7504            return;
 7505        };
 7506        if self.selections.count() != 1 {
 7507            return;
 7508        }
 7509
 7510        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7511
 7512        match &active_edit_prediction.completion {
 7513            EditPrediction::Move { target, .. } => {
 7514                let target = *target;
 7515                self.change_selections(
 7516                    SelectionEffects::scroll(Autoscroll::newest()),
 7517                    window,
 7518                    cx,
 7519                    |selections| {
 7520                        selections.select_anchor_ranges([target..target]);
 7521                    },
 7522                );
 7523            }
 7524            EditPrediction::Edit { edits, .. } => {
 7525                // Find an insertion that starts at the cursor position.
 7526                let snapshot = self.buffer.read(cx).snapshot(cx);
 7527                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7528                let insertion = edits.iter().find_map(|(range, text)| {
 7529                    let range = range.to_offset(&snapshot);
 7530                    if range.is_empty() && range.start == cursor_offset {
 7531                        Some(text)
 7532                    } else {
 7533                        None
 7534                    }
 7535                });
 7536
 7537                if let Some(text) = insertion {
 7538                    let mut partial_completion = text
 7539                        .chars()
 7540                        .by_ref()
 7541                        .take_while(|c| c.is_alphabetic())
 7542                        .collect::<String>();
 7543                    if partial_completion.is_empty() {
 7544                        partial_completion = text
 7545                            .chars()
 7546                            .by_ref()
 7547                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7548                            .collect::<String>();
 7549                    }
 7550
 7551                    cx.emit(EditorEvent::InputHandled {
 7552                        utf16_range_to_replace: None,
 7553                        text: partial_completion.clone().into(),
 7554                    });
 7555
 7556                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7557
 7558                    self.refresh_edit_prediction(true, true, window, cx);
 7559                    cx.notify();
 7560                } else {
 7561                    self.accept_edit_prediction(&Default::default(), window, cx);
 7562                }
 7563            }
 7564        }
 7565    }
 7566
 7567    fn discard_edit_prediction(
 7568        &mut self,
 7569        should_report_edit_prediction_event: bool,
 7570        cx: &mut Context<Self>,
 7571    ) -> bool {
 7572        if should_report_edit_prediction_event {
 7573            let completion_id = self
 7574                .active_edit_prediction
 7575                .as_ref()
 7576                .and_then(|active_completion| active_completion.completion_id.clone());
 7577
 7578            self.report_edit_prediction_event(completion_id, false, cx);
 7579        }
 7580
 7581        if let Some(provider) = self.edit_prediction_provider() {
 7582            provider.discard(cx);
 7583        }
 7584
 7585        self.take_active_edit_prediction(cx)
 7586    }
 7587
 7588    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7589        let Some(provider) = self.edit_prediction_provider() else {
 7590            return;
 7591        };
 7592
 7593        let Some((_, buffer, _)) = self
 7594            .buffer
 7595            .read(cx)
 7596            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7597        else {
 7598            return;
 7599        };
 7600
 7601        let extension = buffer
 7602            .read(cx)
 7603            .file()
 7604            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7605
 7606        let event_type = match accepted {
 7607            true => "Edit Prediction Accepted",
 7608            false => "Edit Prediction Discarded",
 7609        };
 7610        telemetry::event!(
 7611            event_type,
 7612            provider = provider.name(),
 7613            prediction_id = id,
 7614            suggestion_accepted = accepted,
 7615            file_extension = extension,
 7616        );
 7617    }
 7618
 7619    pub fn has_active_edit_prediction(&self) -> bool {
 7620        self.active_edit_prediction.is_some()
 7621    }
 7622
 7623    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7624        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7625            return false;
 7626        };
 7627
 7628        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7629        self.clear_highlights::<EditPredictionHighlight>(cx);
 7630        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7631        true
 7632    }
 7633
 7634    /// Returns true when we're displaying the edit prediction popover below the cursor
 7635    /// like we are not previewing and the LSP autocomplete menu is visible
 7636    /// or we are in `when_holding_modifier` mode.
 7637    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7638        if self.edit_prediction_preview_is_active()
 7639            || !self.show_edit_predictions_in_menu()
 7640            || !self.edit_predictions_enabled()
 7641        {
 7642            return false;
 7643        }
 7644
 7645        if self.has_visible_completions_menu() {
 7646            return true;
 7647        }
 7648
 7649        has_completion && self.edit_prediction_requires_modifier()
 7650    }
 7651
 7652    fn handle_modifiers_changed(
 7653        &mut self,
 7654        modifiers: Modifiers,
 7655        position_map: &PositionMap,
 7656        window: &mut Window,
 7657        cx: &mut Context<Self>,
 7658    ) {
 7659        if self.show_edit_predictions_in_menu() {
 7660            self.update_edit_prediction_preview(&modifiers, window, cx);
 7661        }
 7662
 7663        self.update_selection_mode(&modifiers, position_map, window, cx);
 7664
 7665        let mouse_position = window.mouse_position();
 7666        if !position_map.text_hitbox.is_hovered(window) {
 7667            return;
 7668        }
 7669
 7670        self.update_hovered_link(
 7671            position_map.point_for_position(mouse_position),
 7672            &position_map.snapshot,
 7673            modifiers,
 7674            window,
 7675            cx,
 7676        )
 7677    }
 7678
 7679    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7680        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7681        if invert {
 7682            match multi_cursor_setting {
 7683                MultiCursorModifier::Alt => modifiers.alt,
 7684                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7685            }
 7686        } else {
 7687            match multi_cursor_setting {
 7688                MultiCursorModifier::Alt => modifiers.secondary(),
 7689                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7690            }
 7691        }
 7692    }
 7693
 7694    fn columnar_selection_mode(
 7695        modifiers: &Modifiers,
 7696        cx: &mut Context<Self>,
 7697    ) -> Option<ColumnarMode> {
 7698        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7699            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7700                Some(ColumnarMode::FromMouse)
 7701            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7702                Some(ColumnarMode::FromSelection)
 7703            } else {
 7704                None
 7705            }
 7706        } else {
 7707            None
 7708        }
 7709    }
 7710
 7711    fn update_selection_mode(
 7712        &mut self,
 7713        modifiers: &Modifiers,
 7714        position_map: &PositionMap,
 7715        window: &mut Window,
 7716        cx: &mut Context<Self>,
 7717    ) {
 7718        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7719            return;
 7720        };
 7721        if self.selections.pending.is_none() {
 7722            return;
 7723        }
 7724
 7725        let mouse_position = window.mouse_position();
 7726        let point_for_position = position_map.point_for_position(mouse_position);
 7727        let position = point_for_position.previous_valid;
 7728
 7729        self.select(
 7730            SelectPhase::BeginColumnar {
 7731                position,
 7732                reset: false,
 7733                mode,
 7734                goal_column: point_for_position.exact_unclipped.column(),
 7735            },
 7736            window,
 7737            cx,
 7738        );
 7739    }
 7740
 7741    fn update_edit_prediction_preview(
 7742        &mut self,
 7743        modifiers: &Modifiers,
 7744        window: &mut Window,
 7745        cx: &mut Context<Self>,
 7746    ) {
 7747        let mut modifiers_held = false;
 7748        if let Some(accept_keystroke) = self
 7749            .accept_edit_prediction_keybind(false, window, cx)
 7750            .keystroke()
 7751        {
 7752            modifiers_held = modifiers_held
 7753                || (accept_keystroke.modifiers() == modifiers
 7754                    && accept_keystroke.modifiers().modified());
 7755        };
 7756        if let Some(accept_partial_keystroke) = self
 7757            .accept_edit_prediction_keybind(true, window, cx)
 7758            .keystroke()
 7759        {
 7760            modifiers_held = modifiers_held
 7761                || (accept_partial_keystroke.modifiers() == modifiers
 7762                    && accept_partial_keystroke.modifiers().modified());
 7763        }
 7764
 7765        if modifiers_held {
 7766            if matches!(
 7767                self.edit_prediction_preview,
 7768                EditPredictionPreview::Inactive { .. }
 7769            ) {
 7770                self.edit_prediction_preview = EditPredictionPreview::Active {
 7771                    previous_scroll_position: None,
 7772                    since: Instant::now(),
 7773                };
 7774
 7775                self.update_visible_edit_prediction(window, cx);
 7776                cx.notify();
 7777            }
 7778        } else if let EditPredictionPreview::Active {
 7779            previous_scroll_position,
 7780            since,
 7781        } = self.edit_prediction_preview
 7782        {
 7783            if let (Some(previous_scroll_position), Some(position_map)) =
 7784                (previous_scroll_position, self.last_position_map.as_ref())
 7785            {
 7786                self.set_scroll_position(
 7787                    previous_scroll_position
 7788                        .scroll_position(&position_map.snapshot.display_snapshot),
 7789                    window,
 7790                    cx,
 7791                );
 7792            }
 7793
 7794            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7795                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7796            };
 7797            self.clear_row_highlights::<EditPredictionPreview>();
 7798            self.update_visible_edit_prediction(window, cx);
 7799            cx.notify();
 7800        }
 7801    }
 7802
 7803    fn update_visible_edit_prediction(
 7804        &mut self,
 7805        _window: &mut Window,
 7806        cx: &mut Context<Self>,
 7807    ) -> Option<()> {
 7808        if DisableAiSettings::get_global(cx).disable_ai {
 7809            return None;
 7810        }
 7811
 7812        if self.ime_transaction.is_some() {
 7813            self.discard_edit_prediction(false, cx);
 7814            return None;
 7815        }
 7816
 7817        let selection = self.selections.newest_anchor();
 7818        let cursor = selection.head();
 7819        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7820        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7821        let excerpt_id = cursor.excerpt_id;
 7822
 7823        let show_in_menu = self.show_edit_predictions_in_menu();
 7824        let completions_menu_has_precedence = !show_in_menu
 7825            && (self.context_menu.borrow().is_some()
 7826                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7827
 7828        if completions_menu_has_precedence
 7829            || !offset_selection.is_empty()
 7830            || self
 7831                .active_edit_prediction
 7832                .as_ref()
 7833                .is_some_and(|completion| {
 7834                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7835                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7836                    !invalidation_range.contains(&offset_selection.head())
 7837                })
 7838        {
 7839            self.discard_edit_prediction(false, cx);
 7840            return None;
 7841        }
 7842
 7843        self.take_active_edit_prediction(cx);
 7844        let Some(provider) = self.edit_prediction_provider() else {
 7845            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7846            return None;
 7847        };
 7848
 7849        let (buffer, cursor_buffer_position) =
 7850            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7851
 7852        self.edit_prediction_settings =
 7853            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7854
 7855        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7856
 7857        if self.edit_prediction_indent_conflict {
 7858            let cursor_point = cursor.to_point(&multibuffer);
 7859
 7860            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7861
 7862            if let Some((_, indent)) = indents.iter().next()
 7863                && indent.len == cursor_point.column
 7864            {
 7865                self.edit_prediction_indent_conflict = false;
 7866            }
 7867        }
 7868
 7869        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7870        let edits = edit_prediction
 7871            .edits
 7872            .into_iter()
 7873            .flat_map(|(range, new_text)| {
 7874                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7875                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7876                Some((start..end, new_text))
 7877            })
 7878            .collect::<Vec<_>>();
 7879        if edits.is_empty() {
 7880            return None;
 7881        }
 7882
 7883        let first_edit_start = edits.first().unwrap().0.start;
 7884        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7885        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7886
 7887        let last_edit_end = edits.last().unwrap().0.end;
 7888        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7889        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7890
 7891        let cursor_row = cursor.to_point(&multibuffer).row;
 7892
 7893        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7894
 7895        let mut inlay_ids = Vec::new();
 7896        let invalidation_row_range;
 7897        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7898            Some(cursor_row..edit_end_row)
 7899        } else if cursor_row > edit_end_row {
 7900            Some(edit_start_row..cursor_row)
 7901        } else {
 7902            None
 7903        };
 7904        let supports_jump = self
 7905            .edit_prediction_provider
 7906            .as_ref()
 7907            .map(|provider| provider.provider.supports_jump_to_edit())
 7908            .unwrap_or(true);
 7909
 7910        let is_move = supports_jump
 7911            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7912        let completion = if is_move {
 7913            invalidation_row_range =
 7914                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7915            let target = first_edit_start;
 7916            EditPrediction::Move { target, snapshot }
 7917        } else {
 7918            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7919                && !self.edit_predictions_hidden_for_vim_mode;
 7920
 7921            if show_completions_in_buffer {
 7922                if edits
 7923                    .iter()
 7924                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7925                {
 7926                    let mut inlays = Vec::new();
 7927                    for (range, new_text) in &edits {
 7928                        let inlay = Inlay::edit_prediction(
 7929                            post_inc(&mut self.next_inlay_id),
 7930                            range.start,
 7931                            new_text.as_str(),
 7932                        );
 7933                        inlay_ids.push(inlay.id);
 7934                        inlays.push(inlay);
 7935                    }
 7936
 7937                    self.splice_inlays(&[], inlays, cx);
 7938                } else {
 7939                    let background_color = cx.theme().status().deleted_background;
 7940                    self.highlight_text::<EditPredictionHighlight>(
 7941                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7942                        HighlightStyle {
 7943                            background_color: Some(background_color),
 7944                            ..Default::default()
 7945                        },
 7946                        cx,
 7947                    );
 7948                }
 7949            }
 7950
 7951            invalidation_row_range = edit_start_row..edit_end_row;
 7952
 7953            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7954                if provider.show_tab_accept_marker() {
 7955                    EditDisplayMode::TabAccept
 7956                } else {
 7957                    EditDisplayMode::Inline
 7958                }
 7959            } else {
 7960                EditDisplayMode::DiffPopover
 7961            };
 7962
 7963            EditPrediction::Edit {
 7964                edits,
 7965                edit_preview: edit_prediction.edit_preview,
 7966                display_mode,
 7967                snapshot,
 7968            }
 7969        };
 7970
 7971        let invalidation_range = multibuffer
 7972            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7973            ..multibuffer.anchor_after(Point::new(
 7974                invalidation_row_range.end,
 7975                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7976            ));
 7977
 7978        self.stale_edit_prediction_in_menu = None;
 7979        self.active_edit_prediction = Some(EditPredictionState {
 7980            inlay_ids,
 7981            completion,
 7982            completion_id: edit_prediction.id,
 7983            invalidation_range,
 7984        });
 7985
 7986        cx.notify();
 7987
 7988        Some(())
 7989    }
 7990
 7991    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7992        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7993    }
 7994
 7995    fn clear_tasks(&mut self) {
 7996        self.tasks.clear()
 7997    }
 7998
 7999    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8000        if self.tasks.insert(key, value).is_some() {
 8001            // This case should hopefully be rare, but just in case...
 8002            log::error!(
 8003                "multiple different run targets found on a single line, only the last target will be rendered"
 8004            )
 8005        }
 8006    }
 8007
 8008    /// Get all display points of breakpoints that will be rendered within editor
 8009    ///
 8010    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8011    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8012    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8013    fn active_breakpoints(
 8014        &self,
 8015        range: Range<DisplayRow>,
 8016        window: &mut Window,
 8017        cx: &mut Context<Self>,
 8018    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8019        let mut breakpoint_display_points = HashMap::default();
 8020
 8021        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8022            return breakpoint_display_points;
 8023        };
 8024
 8025        let snapshot = self.snapshot(window, cx);
 8026
 8027        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 8028        let Some(project) = self.project() else {
 8029            return breakpoint_display_points;
 8030        };
 8031
 8032        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8033            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8034
 8035        for (buffer_snapshot, range, excerpt_id) in
 8036            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8037        {
 8038            let Some(buffer) = project
 8039                .read(cx)
 8040                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8041            else {
 8042                continue;
 8043            };
 8044            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8045                &buffer,
 8046                Some(
 8047                    buffer_snapshot.anchor_before(range.start)
 8048                        ..buffer_snapshot.anchor_after(range.end),
 8049                ),
 8050                buffer_snapshot,
 8051                cx,
 8052            );
 8053            for (breakpoint, state) in breakpoints {
 8054                let multi_buffer_anchor =
 8055                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8056                let position = multi_buffer_anchor
 8057                    .to_point(multi_buffer_snapshot)
 8058                    .to_display_point(&snapshot);
 8059
 8060                breakpoint_display_points.insert(
 8061                    position.row(),
 8062                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8063                );
 8064            }
 8065        }
 8066
 8067        breakpoint_display_points
 8068    }
 8069
 8070    fn breakpoint_context_menu(
 8071        &self,
 8072        anchor: Anchor,
 8073        window: &mut Window,
 8074        cx: &mut Context<Self>,
 8075    ) -> Entity<ui::ContextMenu> {
 8076        let weak_editor = cx.weak_entity();
 8077        let focus_handle = self.focus_handle(cx);
 8078
 8079        let row = self
 8080            .buffer
 8081            .read(cx)
 8082            .snapshot(cx)
 8083            .summary_for_anchor::<Point>(&anchor)
 8084            .row;
 8085
 8086        let breakpoint = self
 8087            .breakpoint_at_row(row, window, cx)
 8088            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8089
 8090        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8091            "Edit Log Breakpoint"
 8092        } else {
 8093            "Set Log Breakpoint"
 8094        };
 8095
 8096        let condition_breakpoint_msg = if breakpoint
 8097            .as_ref()
 8098            .is_some_and(|bp| bp.1.condition.is_some())
 8099        {
 8100            "Edit Condition Breakpoint"
 8101        } else {
 8102            "Set Condition Breakpoint"
 8103        };
 8104
 8105        let hit_condition_breakpoint_msg = if breakpoint
 8106            .as_ref()
 8107            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8108        {
 8109            "Edit Hit Condition Breakpoint"
 8110        } else {
 8111            "Set Hit Condition Breakpoint"
 8112        };
 8113
 8114        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8115            "Unset Breakpoint"
 8116        } else {
 8117            "Set Breakpoint"
 8118        };
 8119
 8120        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8121
 8122        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8123            BreakpointState::Enabled => Some("Disable"),
 8124            BreakpointState::Disabled => Some("Enable"),
 8125        });
 8126
 8127        let (anchor, breakpoint) =
 8128            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8129
 8130        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8131            menu.on_blur_subscription(Subscription::new(|| {}))
 8132                .context(focus_handle)
 8133                .when(run_to_cursor, |this| {
 8134                    let weak_editor = weak_editor.clone();
 8135                    this.entry("Run to cursor", None, move |window, cx| {
 8136                        weak_editor
 8137                            .update(cx, |editor, cx| {
 8138                                editor.change_selections(
 8139                                    SelectionEffects::no_scroll(),
 8140                                    window,
 8141                                    cx,
 8142                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8143                                );
 8144                            })
 8145                            .ok();
 8146
 8147                        window.dispatch_action(Box::new(RunToCursor), cx);
 8148                    })
 8149                    .separator()
 8150                })
 8151                .when_some(toggle_state_msg, |this, msg| {
 8152                    this.entry(msg, None, {
 8153                        let weak_editor = weak_editor.clone();
 8154                        let breakpoint = breakpoint.clone();
 8155                        move |_window, cx| {
 8156                            weak_editor
 8157                                .update(cx, |this, cx| {
 8158                                    this.edit_breakpoint_at_anchor(
 8159                                        anchor,
 8160                                        breakpoint.as_ref().clone(),
 8161                                        BreakpointEditAction::InvertState,
 8162                                        cx,
 8163                                    );
 8164                                })
 8165                                .log_err();
 8166                        }
 8167                    })
 8168                })
 8169                .entry(set_breakpoint_msg, None, {
 8170                    let weak_editor = weak_editor.clone();
 8171                    let breakpoint = breakpoint.clone();
 8172                    move |_window, cx| {
 8173                        weak_editor
 8174                            .update(cx, |this, cx| {
 8175                                this.edit_breakpoint_at_anchor(
 8176                                    anchor,
 8177                                    breakpoint.as_ref().clone(),
 8178                                    BreakpointEditAction::Toggle,
 8179                                    cx,
 8180                                );
 8181                            })
 8182                            .log_err();
 8183                    }
 8184                })
 8185                .entry(log_breakpoint_msg, None, {
 8186                    let breakpoint = breakpoint.clone();
 8187                    let weak_editor = weak_editor.clone();
 8188                    move |window, cx| {
 8189                        weak_editor
 8190                            .update(cx, |this, cx| {
 8191                                this.add_edit_breakpoint_block(
 8192                                    anchor,
 8193                                    breakpoint.as_ref(),
 8194                                    BreakpointPromptEditAction::Log,
 8195                                    window,
 8196                                    cx,
 8197                                );
 8198                            })
 8199                            .log_err();
 8200                    }
 8201                })
 8202                .entry(condition_breakpoint_msg, None, {
 8203                    let breakpoint = breakpoint.clone();
 8204                    let weak_editor = weak_editor.clone();
 8205                    move |window, cx| {
 8206                        weak_editor
 8207                            .update(cx, |this, cx| {
 8208                                this.add_edit_breakpoint_block(
 8209                                    anchor,
 8210                                    breakpoint.as_ref(),
 8211                                    BreakpointPromptEditAction::Condition,
 8212                                    window,
 8213                                    cx,
 8214                                );
 8215                            })
 8216                            .log_err();
 8217                    }
 8218                })
 8219                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8220                    weak_editor
 8221                        .update(cx, |this, cx| {
 8222                            this.add_edit_breakpoint_block(
 8223                                anchor,
 8224                                breakpoint.as_ref(),
 8225                                BreakpointPromptEditAction::HitCondition,
 8226                                window,
 8227                                cx,
 8228                            );
 8229                        })
 8230                        .log_err();
 8231                })
 8232        })
 8233    }
 8234
 8235    fn render_breakpoint(
 8236        &self,
 8237        position: Anchor,
 8238        row: DisplayRow,
 8239        breakpoint: &Breakpoint,
 8240        state: Option<BreakpointSessionState>,
 8241        cx: &mut Context<Self>,
 8242    ) -> IconButton {
 8243        let is_rejected = state.is_some_and(|s| !s.verified);
 8244        // Is it a breakpoint that shows up when hovering over gutter?
 8245        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8246            (false, false),
 8247            |PhantomBreakpointIndicator {
 8248                 is_active,
 8249                 display_row,
 8250                 collides_with_existing_breakpoint,
 8251             }| {
 8252                (
 8253                    is_active && display_row == row,
 8254                    collides_with_existing_breakpoint,
 8255                )
 8256            },
 8257        );
 8258
 8259        let (color, icon) = {
 8260            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8261                (false, false) => ui::IconName::DebugBreakpoint,
 8262                (true, false) => ui::IconName::DebugLogBreakpoint,
 8263                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8264                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8265            };
 8266
 8267            let color = if is_phantom {
 8268                Color::Hint
 8269            } else if is_rejected {
 8270                Color::Disabled
 8271            } else {
 8272                Color::Debugger
 8273            };
 8274
 8275            (color, icon)
 8276        };
 8277
 8278        let breakpoint = Arc::from(breakpoint.clone());
 8279
 8280        let alt_as_text = gpui::Keystroke {
 8281            modifiers: Modifiers::secondary_key(),
 8282            ..Default::default()
 8283        };
 8284        let primary_action_text = if breakpoint.is_disabled() {
 8285            "Enable breakpoint"
 8286        } else if is_phantom && !collides_with_existing {
 8287            "Set breakpoint"
 8288        } else {
 8289            "Unset breakpoint"
 8290        };
 8291        let focus_handle = self.focus_handle.clone();
 8292
 8293        let meta = if is_rejected {
 8294            SharedString::from("No executable code is associated with this line.")
 8295        } else if collides_with_existing && !breakpoint.is_disabled() {
 8296            SharedString::from(format!(
 8297                "{alt_as_text}-click to disable,\nright-click for more options."
 8298            ))
 8299        } else {
 8300            SharedString::from("Right-click for more options.")
 8301        };
 8302        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8303            .icon_size(IconSize::XSmall)
 8304            .size(ui::ButtonSize::None)
 8305            .when(is_rejected, |this| {
 8306                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8307            })
 8308            .icon_color(color)
 8309            .style(ButtonStyle::Transparent)
 8310            .on_click(cx.listener({
 8311                move |editor, event: &ClickEvent, window, cx| {
 8312                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8313                        BreakpointEditAction::InvertState
 8314                    } else {
 8315                        BreakpointEditAction::Toggle
 8316                    };
 8317
 8318                    window.focus(&editor.focus_handle(cx));
 8319                    editor.edit_breakpoint_at_anchor(
 8320                        position,
 8321                        breakpoint.as_ref().clone(),
 8322                        edit_action,
 8323                        cx,
 8324                    );
 8325                }
 8326            }))
 8327            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8328                editor.set_breakpoint_context_menu(
 8329                    row,
 8330                    Some(position),
 8331                    event.position(),
 8332                    window,
 8333                    cx,
 8334                );
 8335            }))
 8336            .tooltip(move |window, cx| {
 8337                Tooltip::with_meta_in(
 8338                    primary_action_text,
 8339                    Some(&ToggleBreakpoint),
 8340                    meta.clone(),
 8341                    &focus_handle,
 8342                    window,
 8343                    cx,
 8344                )
 8345            })
 8346    }
 8347
 8348    fn build_tasks_context(
 8349        project: &Entity<Project>,
 8350        buffer: &Entity<Buffer>,
 8351        buffer_row: u32,
 8352        tasks: &Arc<RunnableTasks>,
 8353        cx: &mut Context<Self>,
 8354    ) -> Task<Option<task::TaskContext>> {
 8355        let position = Point::new(buffer_row, tasks.column);
 8356        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8357        let location = Location {
 8358            buffer: buffer.clone(),
 8359            range: range_start..range_start,
 8360        };
 8361        // Fill in the environmental variables from the tree-sitter captures
 8362        let mut captured_task_variables = TaskVariables::default();
 8363        for (capture_name, value) in tasks.extra_variables.clone() {
 8364            captured_task_variables.insert(
 8365                task::VariableName::Custom(capture_name.into()),
 8366                value.clone(),
 8367            );
 8368        }
 8369        project.update(cx, |project, cx| {
 8370            project.task_store().update(cx, |task_store, cx| {
 8371                task_store.task_context_for_location(captured_task_variables, location, cx)
 8372            })
 8373        })
 8374    }
 8375
 8376    pub fn spawn_nearest_task(
 8377        &mut self,
 8378        action: &SpawnNearestTask,
 8379        window: &mut Window,
 8380        cx: &mut Context<Self>,
 8381    ) {
 8382        let Some((workspace, _)) = self.workspace.clone() else {
 8383            return;
 8384        };
 8385        let Some(project) = self.project.clone() else {
 8386            return;
 8387        };
 8388
 8389        // Try to find a closest, enclosing node using tree-sitter that has a task
 8390        let Some((buffer, buffer_row, tasks)) = self
 8391            .find_enclosing_node_task(cx)
 8392            // Or find the task that's closest in row-distance.
 8393            .or_else(|| self.find_closest_task(cx))
 8394        else {
 8395            return;
 8396        };
 8397
 8398        let reveal_strategy = action.reveal;
 8399        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8400        cx.spawn_in(window, async move |_, cx| {
 8401            let context = task_context.await?;
 8402            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8403
 8404            let resolved = &mut resolved_task.resolved;
 8405            resolved.reveal = reveal_strategy;
 8406
 8407            workspace
 8408                .update_in(cx, |workspace, window, cx| {
 8409                    workspace.schedule_resolved_task(
 8410                        task_source_kind,
 8411                        resolved_task,
 8412                        false,
 8413                        window,
 8414                        cx,
 8415                    );
 8416                })
 8417                .ok()
 8418        })
 8419        .detach();
 8420    }
 8421
 8422    fn find_closest_task(
 8423        &mut self,
 8424        cx: &mut Context<Self>,
 8425    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8426        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8427
 8428        let ((buffer_id, row), tasks) = self
 8429            .tasks
 8430            .iter()
 8431            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8432
 8433        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8434        let tasks = Arc::new(tasks.to_owned());
 8435        Some((buffer, *row, tasks))
 8436    }
 8437
 8438    fn find_enclosing_node_task(
 8439        &mut self,
 8440        cx: &mut Context<Self>,
 8441    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8442        let snapshot = self.buffer.read(cx).snapshot(cx);
 8443        let offset = self.selections.newest::<usize>(cx).head();
 8444        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8445        let buffer_id = excerpt.buffer().remote_id();
 8446
 8447        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8448        let mut cursor = layer.node().walk();
 8449
 8450        while cursor.goto_first_child_for_byte(offset).is_some() {
 8451            if cursor.node().end_byte() == offset {
 8452                cursor.goto_next_sibling();
 8453            }
 8454        }
 8455
 8456        // Ascend to the smallest ancestor that contains the range and has a task.
 8457        loop {
 8458            let node = cursor.node();
 8459            let node_range = node.byte_range();
 8460            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8461
 8462            // Check if this node contains our offset
 8463            if node_range.start <= offset && node_range.end >= offset {
 8464                // If it contains offset, check for task
 8465                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8466                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8467                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8468                }
 8469            }
 8470
 8471            if !cursor.goto_parent() {
 8472                break;
 8473            }
 8474        }
 8475        None
 8476    }
 8477
 8478    fn render_run_indicator(
 8479        &self,
 8480        _style: &EditorStyle,
 8481        is_active: bool,
 8482        row: DisplayRow,
 8483        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8484        cx: &mut Context<Self>,
 8485    ) -> IconButton {
 8486        let color = Color::Muted;
 8487        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8488
 8489        IconButton::new(
 8490            ("run_indicator", row.0 as usize),
 8491            ui::IconName::PlayOutlined,
 8492        )
 8493        .shape(ui::IconButtonShape::Square)
 8494        .icon_size(IconSize::XSmall)
 8495        .icon_color(color)
 8496        .toggle_state(is_active)
 8497        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8498            let quick_launch = match e {
 8499                ClickEvent::Keyboard(_) => true,
 8500                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8501            };
 8502
 8503            window.focus(&editor.focus_handle(cx));
 8504            editor.toggle_code_actions(
 8505                &ToggleCodeActions {
 8506                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8507                    quick_launch,
 8508                },
 8509                window,
 8510                cx,
 8511            );
 8512        }))
 8513        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8514            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8515        }))
 8516    }
 8517
 8518    pub fn context_menu_visible(&self) -> bool {
 8519        !self.edit_prediction_preview_is_active()
 8520            && self
 8521                .context_menu
 8522                .borrow()
 8523                .as_ref()
 8524                .is_some_and(|menu| menu.visible())
 8525    }
 8526
 8527    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8528        self.context_menu
 8529            .borrow()
 8530            .as_ref()
 8531            .map(|menu| menu.origin())
 8532    }
 8533
 8534    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8535        self.context_menu_options = Some(options);
 8536    }
 8537
 8538    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8539    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8540
 8541    fn render_edit_prediction_popover(
 8542        &mut self,
 8543        text_bounds: &Bounds<Pixels>,
 8544        content_origin: gpui::Point<Pixels>,
 8545        right_margin: Pixels,
 8546        editor_snapshot: &EditorSnapshot,
 8547        visible_row_range: Range<DisplayRow>,
 8548        scroll_top: f32,
 8549        scroll_bottom: f32,
 8550        line_layouts: &[LineWithInvisibles],
 8551        line_height: Pixels,
 8552        scroll_pixel_position: gpui::Point<Pixels>,
 8553        newest_selection_head: Option<DisplayPoint>,
 8554        editor_width: Pixels,
 8555        style: &EditorStyle,
 8556        window: &mut Window,
 8557        cx: &mut App,
 8558    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8559        if self.mode().is_minimap() {
 8560            return None;
 8561        }
 8562        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8563
 8564        if self.edit_prediction_visible_in_cursor_popover(true) {
 8565            return None;
 8566        }
 8567
 8568        match &active_edit_prediction.completion {
 8569            EditPrediction::Move { target, .. } => {
 8570                let target_display_point = target.to_display_point(editor_snapshot);
 8571
 8572                if self.edit_prediction_requires_modifier() {
 8573                    if !self.edit_prediction_preview_is_active() {
 8574                        return None;
 8575                    }
 8576
 8577                    self.render_edit_prediction_modifier_jump_popover(
 8578                        text_bounds,
 8579                        content_origin,
 8580                        visible_row_range,
 8581                        line_layouts,
 8582                        line_height,
 8583                        scroll_pixel_position,
 8584                        newest_selection_head,
 8585                        target_display_point,
 8586                        window,
 8587                        cx,
 8588                    )
 8589                } else {
 8590                    self.render_edit_prediction_eager_jump_popover(
 8591                        text_bounds,
 8592                        content_origin,
 8593                        editor_snapshot,
 8594                        visible_row_range,
 8595                        scroll_top,
 8596                        scroll_bottom,
 8597                        line_height,
 8598                        scroll_pixel_position,
 8599                        target_display_point,
 8600                        editor_width,
 8601                        window,
 8602                        cx,
 8603                    )
 8604                }
 8605            }
 8606            EditPrediction::Edit {
 8607                display_mode: EditDisplayMode::Inline,
 8608                ..
 8609            } => None,
 8610            EditPrediction::Edit {
 8611                display_mode: EditDisplayMode::TabAccept,
 8612                edits,
 8613                ..
 8614            } => {
 8615                let range = &edits.first()?.0;
 8616                let target_display_point = range.end.to_display_point(editor_snapshot);
 8617
 8618                self.render_edit_prediction_end_of_line_popover(
 8619                    "Accept",
 8620                    editor_snapshot,
 8621                    visible_row_range,
 8622                    target_display_point,
 8623                    line_height,
 8624                    scroll_pixel_position,
 8625                    content_origin,
 8626                    editor_width,
 8627                    window,
 8628                    cx,
 8629                )
 8630            }
 8631            EditPrediction::Edit {
 8632                edits,
 8633                edit_preview,
 8634                display_mode: EditDisplayMode::DiffPopover,
 8635                snapshot,
 8636            } => self.render_edit_prediction_diff_popover(
 8637                text_bounds,
 8638                content_origin,
 8639                right_margin,
 8640                editor_snapshot,
 8641                visible_row_range,
 8642                line_layouts,
 8643                line_height,
 8644                scroll_pixel_position,
 8645                newest_selection_head,
 8646                editor_width,
 8647                style,
 8648                edits,
 8649                edit_preview,
 8650                snapshot,
 8651                window,
 8652                cx,
 8653            ),
 8654        }
 8655    }
 8656
 8657    fn render_edit_prediction_modifier_jump_popover(
 8658        &mut self,
 8659        text_bounds: &Bounds<Pixels>,
 8660        content_origin: gpui::Point<Pixels>,
 8661        visible_row_range: Range<DisplayRow>,
 8662        line_layouts: &[LineWithInvisibles],
 8663        line_height: Pixels,
 8664        scroll_pixel_position: gpui::Point<Pixels>,
 8665        newest_selection_head: Option<DisplayPoint>,
 8666        target_display_point: DisplayPoint,
 8667        window: &mut Window,
 8668        cx: &mut App,
 8669    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8670        let scrolled_content_origin =
 8671            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8672
 8673        const SCROLL_PADDING_Y: Pixels = px(12.);
 8674
 8675        if target_display_point.row() < visible_row_range.start {
 8676            return self.render_edit_prediction_scroll_popover(
 8677                |_| SCROLL_PADDING_Y,
 8678                IconName::ArrowUp,
 8679                visible_row_range,
 8680                line_layouts,
 8681                newest_selection_head,
 8682                scrolled_content_origin,
 8683                window,
 8684                cx,
 8685            );
 8686        } else if target_display_point.row() >= visible_row_range.end {
 8687            return self.render_edit_prediction_scroll_popover(
 8688                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8689                IconName::ArrowDown,
 8690                visible_row_range,
 8691                line_layouts,
 8692                newest_selection_head,
 8693                scrolled_content_origin,
 8694                window,
 8695                cx,
 8696            );
 8697        }
 8698
 8699        const POLE_WIDTH: Pixels = px(2.);
 8700
 8701        let line_layout =
 8702            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8703        let target_column = target_display_point.column() as usize;
 8704
 8705        let target_x = line_layout.x_for_index(target_column);
 8706        let target_y =
 8707            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8708
 8709        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8710
 8711        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8712        border_color.l += 0.001;
 8713
 8714        let mut element = v_flex()
 8715            .items_end()
 8716            .when(flag_on_right, |el| el.items_start())
 8717            .child(if flag_on_right {
 8718                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8719                    .rounded_bl(px(0.))
 8720                    .rounded_tl(px(0.))
 8721                    .border_l_2()
 8722                    .border_color(border_color)
 8723            } else {
 8724                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8725                    .rounded_br(px(0.))
 8726                    .rounded_tr(px(0.))
 8727                    .border_r_2()
 8728                    .border_color(border_color)
 8729            })
 8730            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8731            .into_any();
 8732
 8733        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8734
 8735        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8736            - point(
 8737                if flag_on_right {
 8738                    POLE_WIDTH
 8739                } else {
 8740                    size.width - POLE_WIDTH
 8741                },
 8742                size.height - line_height,
 8743            );
 8744
 8745        origin.x = origin.x.max(content_origin.x);
 8746
 8747        element.prepaint_at(origin, window, cx);
 8748
 8749        Some((element, origin))
 8750    }
 8751
 8752    fn render_edit_prediction_scroll_popover(
 8753        &mut self,
 8754        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8755        scroll_icon: IconName,
 8756        visible_row_range: Range<DisplayRow>,
 8757        line_layouts: &[LineWithInvisibles],
 8758        newest_selection_head: Option<DisplayPoint>,
 8759        scrolled_content_origin: gpui::Point<Pixels>,
 8760        window: &mut Window,
 8761        cx: &mut App,
 8762    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8763        let mut element = self
 8764            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8765            .into_any();
 8766
 8767        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8768
 8769        let cursor = newest_selection_head?;
 8770        let cursor_row_layout =
 8771            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8772        let cursor_column = cursor.column() as usize;
 8773
 8774        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8775
 8776        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8777
 8778        element.prepaint_at(origin, window, cx);
 8779        Some((element, origin))
 8780    }
 8781
 8782    fn render_edit_prediction_eager_jump_popover(
 8783        &mut self,
 8784        text_bounds: &Bounds<Pixels>,
 8785        content_origin: gpui::Point<Pixels>,
 8786        editor_snapshot: &EditorSnapshot,
 8787        visible_row_range: Range<DisplayRow>,
 8788        scroll_top: f32,
 8789        scroll_bottom: f32,
 8790        line_height: Pixels,
 8791        scroll_pixel_position: gpui::Point<Pixels>,
 8792        target_display_point: DisplayPoint,
 8793        editor_width: Pixels,
 8794        window: &mut Window,
 8795        cx: &mut App,
 8796    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8797        if target_display_point.row().as_f32() < scroll_top {
 8798            let mut element = self
 8799                .render_edit_prediction_line_popover(
 8800                    "Jump to Edit",
 8801                    Some(IconName::ArrowUp),
 8802                    window,
 8803                    cx,
 8804                )?
 8805                .into_any();
 8806
 8807            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8808            let offset = point(
 8809                (text_bounds.size.width - size.width) / 2.,
 8810                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8811            );
 8812
 8813            let origin = text_bounds.origin + offset;
 8814            element.prepaint_at(origin, window, cx);
 8815            Some((element, origin))
 8816        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8817            let mut element = self
 8818                .render_edit_prediction_line_popover(
 8819                    "Jump to Edit",
 8820                    Some(IconName::ArrowDown),
 8821                    window,
 8822                    cx,
 8823                )?
 8824                .into_any();
 8825
 8826            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8827            let offset = point(
 8828                (text_bounds.size.width - size.width) / 2.,
 8829                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8830            );
 8831
 8832            let origin = text_bounds.origin + offset;
 8833            element.prepaint_at(origin, window, cx);
 8834            Some((element, origin))
 8835        } else {
 8836            self.render_edit_prediction_end_of_line_popover(
 8837                "Jump to Edit",
 8838                editor_snapshot,
 8839                visible_row_range,
 8840                target_display_point,
 8841                line_height,
 8842                scroll_pixel_position,
 8843                content_origin,
 8844                editor_width,
 8845                window,
 8846                cx,
 8847            )
 8848        }
 8849    }
 8850
 8851    fn render_edit_prediction_end_of_line_popover(
 8852        self: &mut Editor,
 8853        label: &'static str,
 8854        editor_snapshot: &EditorSnapshot,
 8855        visible_row_range: Range<DisplayRow>,
 8856        target_display_point: DisplayPoint,
 8857        line_height: Pixels,
 8858        scroll_pixel_position: gpui::Point<Pixels>,
 8859        content_origin: gpui::Point<Pixels>,
 8860        editor_width: Pixels,
 8861        window: &mut Window,
 8862        cx: &mut App,
 8863    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8864        let target_line_end = DisplayPoint::new(
 8865            target_display_point.row(),
 8866            editor_snapshot.line_len(target_display_point.row()),
 8867        );
 8868
 8869        let mut element = self
 8870            .render_edit_prediction_line_popover(label, None, window, cx)?
 8871            .into_any();
 8872
 8873        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8874
 8875        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8876
 8877        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8878        let mut origin = start_point
 8879            + line_origin
 8880            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8881        origin.x = origin.x.max(content_origin.x);
 8882
 8883        let max_x = content_origin.x + editor_width - size.width;
 8884
 8885        if origin.x > max_x {
 8886            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8887
 8888            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8889                origin.y += offset;
 8890                IconName::ArrowUp
 8891            } else {
 8892                origin.y -= offset;
 8893                IconName::ArrowDown
 8894            };
 8895
 8896            element = self
 8897                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8898                .into_any();
 8899
 8900            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8901
 8902            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8903        }
 8904
 8905        element.prepaint_at(origin, window, cx);
 8906        Some((element, origin))
 8907    }
 8908
 8909    fn render_edit_prediction_diff_popover(
 8910        self: &Editor,
 8911        text_bounds: &Bounds<Pixels>,
 8912        content_origin: gpui::Point<Pixels>,
 8913        right_margin: Pixels,
 8914        editor_snapshot: &EditorSnapshot,
 8915        visible_row_range: Range<DisplayRow>,
 8916        line_layouts: &[LineWithInvisibles],
 8917        line_height: Pixels,
 8918        scroll_pixel_position: gpui::Point<Pixels>,
 8919        newest_selection_head: Option<DisplayPoint>,
 8920        editor_width: Pixels,
 8921        style: &EditorStyle,
 8922        edits: &Vec<(Range<Anchor>, String)>,
 8923        edit_preview: &Option<language::EditPreview>,
 8924        snapshot: &language::BufferSnapshot,
 8925        window: &mut Window,
 8926        cx: &mut App,
 8927    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8928        let edit_start = edits
 8929            .first()
 8930            .unwrap()
 8931            .0
 8932            .start
 8933            .to_display_point(editor_snapshot);
 8934        let edit_end = edits
 8935            .last()
 8936            .unwrap()
 8937            .0
 8938            .end
 8939            .to_display_point(editor_snapshot);
 8940
 8941        let is_visible = visible_row_range.contains(&edit_start.row())
 8942            || visible_row_range.contains(&edit_end.row());
 8943        if !is_visible {
 8944            return None;
 8945        }
 8946
 8947        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8948            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8949        } else {
 8950            // Fallback for providers without edit_preview
 8951            crate::edit_prediction_fallback_text(edits, cx)
 8952        };
 8953
 8954        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8955        let line_count = highlighted_edits.text.lines().count();
 8956
 8957        const BORDER_WIDTH: Pixels = px(1.);
 8958
 8959        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8960        let has_keybind = keybind.is_some();
 8961
 8962        let mut element = h_flex()
 8963            .items_start()
 8964            .child(
 8965                h_flex()
 8966                    .bg(cx.theme().colors().editor_background)
 8967                    .border(BORDER_WIDTH)
 8968                    .shadow_xs()
 8969                    .border_color(cx.theme().colors().border)
 8970                    .rounded_l_lg()
 8971                    .when(line_count > 1, |el| el.rounded_br_lg())
 8972                    .pr_1()
 8973                    .child(styled_text),
 8974            )
 8975            .child(
 8976                h_flex()
 8977                    .h(line_height + BORDER_WIDTH * 2.)
 8978                    .px_1p5()
 8979                    .gap_1()
 8980                    // Workaround: For some reason, there's a gap if we don't do this
 8981                    .ml(-BORDER_WIDTH)
 8982                    .shadow(vec![gpui::BoxShadow {
 8983                        color: gpui::black().opacity(0.05),
 8984                        offset: point(px(1.), px(1.)),
 8985                        blur_radius: px(2.),
 8986                        spread_radius: px(0.),
 8987                    }])
 8988                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8989                    .border(BORDER_WIDTH)
 8990                    .border_color(cx.theme().colors().border)
 8991                    .rounded_r_lg()
 8992                    .id("edit_prediction_diff_popover_keybind")
 8993                    .when(!has_keybind, |el| {
 8994                        let status_colors = cx.theme().status();
 8995
 8996                        el.bg(status_colors.error_background)
 8997                            .border_color(status_colors.error.opacity(0.6))
 8998                            .child(Icon::new(IconName::Info).color(Color::Error))
 8999                            .cursor_default()
 9000                            .hoverable_tooltip(move |_window, cx| {
 9001                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9002                            })
 9003                    })
 9004                    .children(keybind),
 9005            )
 9006            .into_any();
 9007
 9008        let longest_row =
 9009            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9010        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9011            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9012        } else {
 9013            layout_line(
 9014                longest_row,
 9015                editor_snapshot,
 9016                style,
 9017                editor_width,
 9018                |_| false,
 9019                window,
 9020                cx,
 9021            )
 9022            .width
 9023        };
 9024
 9025        let viewport_bounds =
 9026            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9027                right: -right_margin,
 9028                ..Default::default()
 9029            });
 9030
 9031        let x_after_longest =
 9032            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 9033                - scroll_pixel_position.x;
 9034
 9035        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9036
 9037        // Fully visible if it can be displayed within the window (allow overlapping other
 9038        // panes). However, this is only allowed if the popover starts within text_bounds.
 9039        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9040            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9041
 9042        let mut origin = if can_position_to_the_right {
 9043            point(
 9044                x_after_longest,
 9045                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 9046                    - scroll_pixel_position.y,
 9047            )
 9048        } else {
 9049            let cursor_row = newest_selection_head.map(|head| head.row());
 9050            let above_edit = edit_start
 9051                .row()
 9052                .0
 9053                .checked_sub(line_count as u32)
 9054                .map(DisplayRow);
 9055            let below_edit = Some(edit_end.row() + 1);
 9056            let above_cursor =
 9057                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9058            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9059
 9060            // Place the edit popover adjacent to the edit if there is a location
 9061            // available that is onscreen and does not obscure the cursor. Otherwise,
 9062            // place it adjacent to the cursor.
 9063            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9064                .into_iter()
 9065                .flatten()
 9066                .find(|&start_row| {
 9067                    let end_row = start_row + line_count as u32;
 9068                    visible_row_range.contains(&start_row)
 9069                        && visible_row_range.contains(&end_row)
 9070                        && cursor_row
 9071                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9072                })?;
 9073
 9074            content_origin
 9075                + point(
 9076                    -scroll_pixel_position.x,
 9077                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 9078                )
 9079        };
 9080
 9081        origin.x -= BORDER_WIDTH;
 9082
 9083        window.defer_draw(element, origin, 1);
 9084
 9085        // Do not return an element, since it will already be drawn due to defer_draw.
 9086        None
 9087    }
 9088
 9089    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9090        px(30.)
 9091    }
 9092
 9093    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9094        if self.read_only(cx) {
 9095            cx.theme().players().read_only()
 9096        } else {
 9097            self.style.as_ref().unwrap().local_player
 9098        }
 9099    }
 9100
 9101    fn render_edit_prediction_accept_keybind(
 9102        &self,
 9103        window: &mut Window,
 9104        cx: &App,
 9105    ) -> Option<AnyElement> {
 9106        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9107        let accept_keystroke = accept_binding.keystroke()?;
 9108
 9109        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9110
 9111        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9112            Color::Accent
 9113        } else {
 9114            Color::Muted
 9115        };
 9116
 9117        h_flex()
 9118            .px_0p5()
 9119            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9120            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9121            .text_size(TextSize::XSmall.rems(cx))
 9122            .child(h_flex().children(ui::render_modifiers(
 9123                accept_keystroke.modifiers(),
 9124                PlatformStyle::platform(),
 9125                Some(modifiers_color),
 9126                Some(IconSize::XSmall.rems().into()),
 9127                true,
 9128            )))
 9129            .when(is_platform_style_mac, |parent| {
 9130                parent.child(accept_keystroke.key().to_string())
 9131            })
 9132            .when(!is_platform_style_mac, |parent| {
 9133                parent.child(
 9134                    Key::new(
 9135                        util::capitalize(accept_keystroke.key()),
 9136                        Some(Color::Default),
 9137                    )
 9138                    .size(Some(IconSize::XSmall.rems().into())),
 9139                )
 9140            })
 9141            .into_any()
 9142            .into()
 9143    }
 9144
 9145    fn render_edit_prediction_line_popover(
 9146        &self,
 9147        label: impl Into<SharedString>,
 9148        icon: Option<IconName>,
 9149        window: &mut Window,
 9150        cx: &App,
 9151    ) -> Option<Stateful<Div>> {
 9152        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9153
 9154        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9155        let has_keybind = keybind.is_some();
 9156
 9157        let result = h_flex()
 9158            .id("ep-line-popover")
 9159            .py_0p5()
 9160            .pl_1()
 9161            .pr(padding_right)
 9162            .gap_1()
 9163            .rounded_md()
 9164            .border_1()
 9165            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9166            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9167            .shadow_xs()
 9168            .when(!has_keybind, |el| {
 9169                let status_colors = cx.theme().status();
 9170
 9171                el.bg(status_colors.error_background)
 9172                    .border_color(status_colors.error.opacity(0.6))
 9173                    .pl_2()
 9174                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9175                    .cursor_default()
 9176                    .hoverable_tooltip(move |_window, cx| {
 9177                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9178                    })
 9179            })
 9180            .children(keybind)
 9181            .child(
 9182                Label::new(label)
 9183                    .size(LabelSize::Small)
 9184                    .when(!has_keybind, |el| {
 9185                        el.color(cx.theme().status().error.into()).strikethrough()
 9186                    }),
 9187            )
 9188            .when(!has_keybind, |el| {
 9189                el.child(
 9190                    h_flex().ml_1().child(
 9191                        Icon::new(IconName::Info)
 9192                            .size(IconSize::Small)
 9193                            .color(cx.theme().status().error.into()),
 9194                    ),
 9195                )
 9196            })
 9197            .when_some(icon, |element, icon| {
 9198                element.child(
 9199                    div()
 9200                        .mt(px(1.5))
 9201                        .child(Icon::new(icon).size(IconSize::Small)),
 9202                )
 9203            });
 9204
 9205        Some(result)
 9206    }
 9207
 9208    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9209        let accent_color = cx.theme().colors().text_accent;
 9210        let editor_bg_color = cx.theme().colors().editor_background;
 9211        editor_bg_color.blend(accent_color.opacity(0.1))
 9212    }
 9213
 9214    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9215        let accent_color = cx.theme().colors().text_accent;
 9216        let editor_bg_color = cx.theme().colors().editor_background;
 9217        editor_bg_color.blend(accent_color.opacity(0.6))
 9218    }
 9219    fn get_prediction_provider_icon_name(
 9220        provider: &Option<RegisteredEditPredictionProvider>,
 9221    ) -> IconName {
 9222        match provider {
 9223            Some(provider) => match provider.provider.name() {
 9224                "copilot" => IconName::Copilot,
 9225                "supermaven" => IconName::Supermaven,
 9226                _ => IconName::ZedPredict,
 9227            },
 9228            None => IconName::ZedPredict,
 9229        }
 9230    }
 9231
 9232    fn render_edit_prediction_cursor_popover(
 9233        &self,
 9234        min_width: Pixels,
 9235        max_width: Pixels,
 9236        cursor_point: Point,
 9237        style: &EditorStyle,
 9238        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9239        _window: &Window,
 9240        cx: &mut Context<Editor>,
 9241    ) -> Option<AnyElement> {
 9242        let provider = self.edit_prediction_provider.as_ref()?;
 9243        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9244
 9245        let is_refreshing = provider.provider.is_refreshing(cx);
 9246
 9247        fn pending_completion_container(icon: IconName) -> Div {
 9248            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9249        }
 9250
 9251        let completion = match &self.active_edit_prediction {
 9252            Some(prediction) => {
 9253                if !self.has_visible_completions_menu() {
 9254                    const RADIUS: Pixels = px(6.);
 9255                    const BORDER_WIDTH: Pixels = px(1.);
 9256
 9257                    return Some(
 9258                        h_flex()
 9259                            .elevation_2(cx)
 9260                            .border(BORDER_WIDTH)
 9261                            .border_color(cx.theme().colors().border)
 9262                            .when(accept_keystroke.is_none(), |el| {
 9263                                el.border_color(cx.theme().status().error)
 9264                            })
 9265                            .rounded(RADIUS)
 9266                            .rounded_tl(px(0.))
 9267                            .overflow_hidden()
 9268                            .child(div().px_1p5().child(match &prediction.completion {
 9269                                EditPrediction::Move { target, snapshot } => {
 9270                                    use text::ToPoint as _;
 9271                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9272                                    {
 9273                                        Icon::new(IconName::ZedPredictDown)
 9274                                    } else {
 9275                                        Icon::new(IconName::ZedPredictUp)
 9276                                    }
 9277                                }
 9278                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9279                            }))
 9280                            .child(
 9281                                h_flex()
 9282                                    .gap_1()
 9283                                    .py_1()
 9284                                    .px_2()
 9285                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9286                                    .border_l_1()
 9287                                    .border_color(cx.theme().colors().border)
 9288                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9289                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9290                                        el.child(
 9291                                            Label::new("Hold")
 9292                                                .size(LabelSize::Small)
 9293                                                .when(accept_keystroke.is_none(), |el| {
 9294                                                    el.strikethrough()
 9295                                                })
 9296                                                .line_height_style(LineHeightStyle::UiLabel),
 9297                                        )
 9298                                    })
 9299                                    .id("edit_prediction_cursor_popover_keybind")
 9300                                    .when(accept_keystroke.is_none(), |el| {
 9301                                        let status_colors = cx.theme().status();
 9302
 9303                                        el.bg(status_colors.error_background)
 9304                                            .border_color(status_colors.error.opacity(0.6))
 9305                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9306                                            .cursor_default()
 9307                                            .hoverable_tooltip(move |_window, cx| {
 9308                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9309                                                    .into()
 9310                                            })
 9311                                    })
 9312                                    .when_some(
 9313                                        accept_keystroke.as_ref(),
 9314                                        |el, accept_keystroke| {
 9315                                            el.child(h_flex().children(ui::render_modifiers(
 9316                                                accept_keystroke.modifiers(),
 9317                                                PlatformStyle::platform(),
 9318                                                Some(Color::Default),
 9319                                                Some(IconSize::XSmall.rems().into()),
 9320                                                false,
 9321                                            )))
 9322                                        },
 9323                                    ),
 9324                            )
 9325                            .into_any(),
 9326                    );
 9327                }
 9328
 9329                self.render_edit_prediction_cursor_popover_preview(
 9330                    prediction,
 9331                    cursor_point,
 9332                    style,
 9333                    cx,
 9334                )?
 9335            }
 9336
 9337            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9338                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9339                    stale_completion,
 9340                    cursor_point,
 9341                    style,
 9342                    cx,
 9343                )?,
 9344
 9345                None => pending_completion_container(provider_icon)
 9346                    .child(Label::new("...").size(LabelSize::Small)),
 9347            },
 9348
 9349            None => pending_completion_container(provider_icon)
 9350                .child(Label::new("...").size(LabelSize::Small)),
 9351        };
 9352
 9353        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9354            completion
 9355                .with_animation(
 9356                    "loading-completion",
 9357                    Animation::new(Duration::from_secs(2))
 9358                        .repeat()
 9359                        .with_easing(pulsating_between(0.4, 0.8)),
 9360                    |label, delta| label.opacity(delta),
 9361                )
 9362                .into_any_element()
 9363        } else {
 9364            completion.into_any_element()
 9365        };
 9366
 9367        let has_completion = self.active_edit_prediction.is_some();
 9368
 9369        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9370        Some(
 9371            h_flex()
 9372                .min_w(min_width)
 9373                .max_w(max_width)
 9374                .flex_1()
 9375                .elevation_2(cx)
 9376                .border_color(cx.theme().colors().border)
 9377                .child(
 9378                    div()
 9379                        .flex_1()
 9380                        .py_1()
 9381                        .px_2()
 9382                        .overflow_hidden()
 9383                        .child(completion),
 9384                )
 9385                .when_some(accept_keystroke, |el, accept_keystroke| {
 9386                    if !accept_keystroke.modifiers().modified() {
 9387                        return el;
 9388                    }
 9389
 9390                    el.child(
 9391                        h_flex()
 9392                            .h_full()
 9393                            .border_l_1()
 9394                            .rounded_r_lg()
 9395                            .border_color(cx.theme().colors().border)
 9396                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9397                            .gap_1()
 9398                            .py_1()
 9399                            .px_2()
 9400                            .child(
 9401                                h_flex()
 9402                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9403                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9404                                    .child(h_flex().children(ui::render_modifiers(
 9405                                        accept_keystroke.modifiers(),
 9406                                        PlatformStyle::platform(),
 9407                                        Some(if !has_completion {
 9408                                            Color::Muted
 9409                                        } else {
 9410                                            Color::Default
 9411                                        }),
 9412                                        None,
 9413                                        false,
 9414                                    ))),
 9415                            )
 9416                            .child(Label::new("Preview").into_any_element())
 9417                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9418                    )
 9419                })
 9420                .into_any(),
 9421        )
 9422    }
 9423
 9424    fn render_edit_prediction_cursor_popover_preview(
 9425        &self,
 9426        completion: &EditPredictionState,
 9427        cursor_point: Point,
 9428        style: &EditorStyle,
 9429        cx: &mut Context<Editor>,
 9430    ) -> Option<Div> {
 9431        use text::ToPoint as _;
 9432
 9433        fn render_relative_row_jump(
 9434            prefix: impl Into<String>,
 9435            current_row: u32,
 9436            target_row: u32,
 9437        ) -> Div {
 9438            let (row_diff, arrow) = if target_row < current_row {
 9439                (current_row - target_row, IconName::ArrowUp)
 9440            } else {
 9441                (target_row - current_row, IconName::ArrowDown)
 9442            };
 9443
 9444            h_flex()
 9445                .child(
 9446                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9447                        .color(Color::Muted)
 9448                        .size(LabelSize::Small),
 9449                )
 9450                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9451        }
 9452
 9453        let supports_jump = self
 9454            .edit_prediction_provider
 9455            .as_ref()
 9456            .map(|provider| provider.provider.supports_jump_to_edit())
 9457            .unwrap_or(true);
 9458
 9459        match &completion.completion {
 9460            EditPrediction::Move {
 9461                target, snapshot, ..
 9462            } => {
 9463                if !supports_jump {
 9464                    return None;
 9465                }
 9466
 9467                Some(
 9468                    h_flex()
 9469                        .px_2()
 9470                        .gap_2()
 9471                        .flex_1()
 9472                        .child(
 9473                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9474                                Icon::new(IconName::ZedPredictDown)
 9475                            } else {
 9476                                Icon::new(IconName::ZedPredictUp)
 9477                            },
 9478                        )
 9479                        .child(Label::new("Jump to Edit")),
 9480                )
 9481            }
 9482
 9483            EditPrediction::Edit {
 9484                edits,
 9485                edit_preview,
 9486                snapshot,
 9487                display_mode: _,
 9488            } => {
 9489                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9490
 9491                let (highlighted_edits, has_more_lines) =
 9492                    if let Some(edit_preview) = edit_preview.as_ref() {
 9493                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9494                            .first_line_preview()
 9495                    } else {
 9496                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9497                    };
 9498
 9499                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9500                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9501
 9502                let preview = h_flex()
 9503                    .gap_1()
 9504                    .min_w_16()
 9505                    .child(styled_text)
 9506                    .when(has_more_lines, |parent| parent.child(""));
 9507
 9508                let left = if supports_jump && first_edit_row != cursor_point.row {
 9509                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9510                        .into_any_element()
 9511                } else {
 9512                    let icon_name =
 9513                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9514                    Icon::new(icon_name).into_any_element()
 9515                };
 9516
 9517                Some(
 9518                    h_flex()
 9519                        .h_full()
 9520                        .flex_1()
 9521                        .gap_2()
 9522                        .pr_1()
 9523                        .overflow_x_hidden()
 9524                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9525                        .child(left)
 9526                        .child(preview),
 9527                )
 9528            }
 9529        }
 9530    }
 9531
 9532    pub fn render_context_menu(
 9533        &self,
 9534        style: &EditorStyle,
 9535        max_height_in_lines: u32,
 9536        window: &mut Window,
 9537        cx: &mut Context<Editor>,
 9538    ) -> Option<AnyElement> {
 9539        let menu = self.context_menu.borrow();
 9540        let menu = menu.as_ref()?;
 9541        if !menu.visible() {
 9542            return None;
 9543        };
 9544        Some(menu.render(style, max_height_in_lines, window, cx))
 9545    }
 9546
 9547    fn render_context_menu_aside(
 9548        &mut self,
 9549        max_size: Size<Pixels>,
 9550        window: &mut Window,
 9551        cx: &mut Context<Editor>,
 9552    ) -> Option<AnyElement> {
 9553        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9554            if menu.visible() {
 9555                menu.render_aside(max_size, window, cx)
 9556            } else {
 9557                None
 9558            }
 9559        })
 9560    }
 9561
 9562    fn hide_context_menu(
 9563        &mut self,
 9564        window: &mut Window,
 9565        cx: &mut Context<Self>,
 9566    ) -> Option<CodeContextMenu> {
 9567        cx.notify();
 9568        self.completion_tasks.clear();
 9569        let context_menu = self.context_menu.borrow_mut().take();
 9570        self.stale_edit_prediction_in_menu.take();
 9571        self.update_visible_edit_prediction(window, cx);
 9572        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9573            && let Some(completion_provider) = &self.completion_provider
 9574        {
 9575            completion_provider.selection_changed(None, window, cx);
 9576        }
 9577        context_menu
 9578    }
 9579
 9580    fn show_snippet_choices(
 9581        &mut self,
 9582        choices: &Vec<String>,
 9583        selection: Range<Anchor>,
 9584        cx: &mut Context<Self>,
 9585    ) {
 9586        let Some((_, buffer, _)) = self
 9587            .buffer()
 9588            .read(cx)
 9589            .excerpt_containing(selection.start, cx)
 9590        else {
 9591            return;
 9592        };
 9593        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9594        else {
 9595            return;
 9596        };
 9597        if buffer != end_buffer {
 9598            log::error!("expected anchor range to have matching buffer IDs");
 9599            return;
 9600        }
 9601
 9602        let id = post_inc(&mut self.next_completion_id);
 9603        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9604        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9605            CompletionsMenu::new_snippet_choices(
 9606                id,
 9607                true,
 9608                choices,
 9609                selection,
 9610                buffer,
 9611                snippet_sort_order,
 9612            ),
 9613        ));
 9614    }
 9615
 9616    pub fn insert_snippet(
 9617        &mut self,
 9618        insertion_ranges: &[Range<usize>],
 9619        snippet: Snippet,
 9620        window: &mut Window,
 9621        cx: &mut Context<Self>,
 9622    ) -> Result<()> {
 9623        struct Tabstop<T> {
 9624            is_end_tabstop: bool,
 9625            ranges: Vec<Range<T>>,
 9626            choices: Option<Vec<String>>,
 9627        }
 9628
 9629        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9630            let snippet_text: Arc<str> = snippet.text.clone().into();
 9631            let edits = insertion_ranges
 9632                .iter()
 9633                .cloned()
 9634                .map(|range| (range, snippet_text.clone()));
 9635            let autoindent_mode = AutoindentMode::Block {
 9636                original_indent_columns: Vec::new(),
 9637            };
 9638            buffer.edit(edits, Some(autoindent_mode), cx);
 9639
 9640            let snapshot = &*buffer.read(cx);
 9641            let snippet = &snippet;
 9642            snippet
 9643                .tabstops
 9644                .iter()
 9645                .map(|tabstop| {
 9646                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9647                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9648                    });
 9649                    let mut tabstop_ranges = tabstop
 9650                        .ranges
 9651                        .iter()
 9652                        .flat_map(|tabstop_range| {
 9653                            let mut delta = 0_isize;
 9654                            insertion_ranges.iter().map(move |insertion_range| {
 9655                                let insertion_start = insertion_range.start as isize + delta;
 9656                                delta +=
 9657                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9658
 9659                                let start = ((insertion_start + tabstop_range.start) as usize)
 9660                                    .min(snapshot.len());
 9661                                let end = ((insertion_start + tabstop_range.end) as usize)
 9662                                    .min(snapshot.len());
 9663                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9664                            })
 9665                        })
 9666                        .collect::<Vec<_>>();
 9667                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9668
 9669                    Tabstop {
 9670                        is_end_tabstop,
 9671                        ranges: tabstop_ranges,
 9672                        choices: tabstop.choices.clone(),
 9673                    }
 9674                })
 9675                .collect::<Vec<_>>()
 9676        });
 9677        if let Some(tabstop) = tabstops.first() {
 9678            self.change_selections(Default::default(), window, cx, |s| {
 9679                // Reverse order so that the first range is the newest created selection.
 9680                // Completions will use it and autoscroll will prioritize it.
 9681                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9682            });
 9683
 9684            if let Some(choices) = &tabstop.choices
 9685                && let Some(selection) = tabstop.ranges.first()
 9686            {
 9687                self.show_snippet_choices(choices, selection.clone(), cx)
 9688            }
 9689
 9690            // If we're already at the last tabstop and it's at the end of the snippet,
 9691            // we're done, we don't need to keep the state around.
 9692            if !tabstop.is_end_tabstop {
 9693                let choices = tabstops
 9694                    .iter()
 9695                    .map(|tabstop| tabstop.choices.clone())
 9696                    .collect();
 9697
 9698                let ranges = tabstops
 9699                    .into_iter()
 9700                    .map(|tabstop| tabstop.ranges)
 9701                    .collect::<Vec<_>>();
 9702
 9703                self.snippet_stack.push(SnippetState {
 9704                    active_index: 0,
 9705                    ranges,
 9706                    choices,
 9707                });
 9708            }
 9709
 9710            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9711            if self.autoclose_regions.is_empty() {
 9712                let snapshot = self.buffer.read(cx).snapshot(cx);
 9713                let mut all_selections = self.selections.all::<Point>(cx);
 9714                for selection in &mut all_selections {
 9715                    let selection_head = selection.head();
 9716                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9717                        continue;
 9718                    };
 9719
 9720                    let mut bracket_pair = None;
 9721                    let max_lookup_length = scope
 9722                        .brackets()
 9723                        .map(|(pair, _)| {
 9724                            pair.start
 9725                                .as_str()
 9726                                .chars()
 9727                                .count()
 9728                                .max(pair.end.as_str().chars().count())
 9729                        })
 9730                        .max();
 9731                    if let Some(max_lookup_length) = max_lookup_length {
 9732                        let next_text = snapshot
 9733                            .chars_at(selection_head)
 9734                            .take(max_lookup_length)
 9735                            .collect::<String>();
 9736                        let prev_text = snapshot
 9737                            .reversed_chars_at(selection_head)
 9738                            .take(max_lookup_length)
 9739                            .collect::<String>();
 9740
 9741                        for (pair, enabled) in scope.brackets() {
 9742                            if enabled
 9743                                && pair.close
 9744                                && prev_text.starts_with(pair.start.as_str())
 9745                                && next_text.starts_with(pair.end.as_str())
 9746                            {
 9747                                bracket_pair = Some(pair.clone());
 9748                                break;
 9749                            }
 9750                        }
 9751                    }
 9752
 9753                    if let Some(pair) = bracket_pair {
 9754                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9755                        let autoclose_enabled =
 9756                            self.use_autoclose && snapshot_settings.use_autoclose;
 9757                        if autoclose_enabled {
 9758                            let start = snapshot.anchor_after(selection_head);
 9759                            let end = snapshot.anchor_after(selection_head);
 9760                            self.autoclose_regions.push(AutocloseRegion {
 9761                                selection_id: selection.id,
 9762                                range: start..end,
 9763                                pair,
 9764                            });
 9765                        }
 9766                    }
 9767                }
 9768            }
 9769        }
 9770        Ok(())
 9771    }
 9772
 9773    pub fn move_to_next_snippet_tabstop(
 9774        &mut self,
 9775        window: &mut Window,
 9776        cx: &mut Context<Self>,
 9777    ) -> bool {
 9778        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9779    }
 9780
 9781    pub fn move_to_prev_snippet_tabstop(
 9782        &mut self,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) -> bool {
 9786        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9787    }
 9788
 9789    pub fn move_to_snippet_tabstop(
 9790        &mut self,
 9791        bias: Bias,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) -> bool {
 9795        if let Some(mut snippet) = self.snippet_stack.pop() {
 9796            match bias {
 9797                Bias::Left => {
 9798                    if snippet.active_index > 0 {
 9799                        snippet.active_index -= 1;
 9800                    } else {
 9801                        self.snippet_stack.push(snippet);
 9802                        return false;
 9803                    }
 9804                }
 9805                Bias::Right => {
 9806                    if snippet.active_index + 1 < snippet.ranges.len() {
 9807                        snippet.active_index += 1;
 9808                    } else {
 9809                        self.snippet_stack.push(snippet);
 9810                        return false;
 9811                    }
 9812                }
 9813            }
 9814            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9815                self.change_selections(Default::default(), window, cx, |s| {
 9816                    // Reverse order so that the first range is the newest created selection.
 9817                    // Completions will use it and autoscroll will prioritize it.
 9818                    s.select_ranges(current_ranges.iter().rev().cloned())
 9819                });
 9820
 9821                if let Some(choices) = &snippet.choices[snippet.active_index]
 9822                    && let Some(selection) = current_ranges.first()
 9823                {
 9824                    self.show_snippet_choices(choices, selection.clone(), cx);
 9825                }
 9826
 9827                // If snippet state is not at the last tabstop, push it back on the stack
 9828                if snippet.active_index + 1 < snippet.ranges.len() {
 9829                    self.snippet_stack.push(snippet);
 9830                }
 9831                return true;
 9832            }
 9833        }
 9834
 9835        false
 9836    }
 9837
 9838    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9839        self.transact(window, cx, |this, window, cx| {
 9840            this.select_all(&SelectAll, window, cx);
 9841            this.insert("", window, cx);
 9842        });
 9843    }
 9844
 9845    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9846        if self.read_only(cx) {
 9847            return;
 9848        }
 9849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9850        self.transact(window, cx, |this, window, cx| {
 9851            this.select_autoclose_pair(window, cx);
 9852            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9853            if !this.linked_edit_ranges.is_empty() {
 9854                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9855                let snapshot = this.buffer.read(cx).snapshot(cx);
 9856
 9857                for selection in selections.iter() {
 9858                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9859                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9860                    if selection_start.buffer_id != selection_end.buffer_id {
 9861                        continue;
 9862                    }
 9863                    if let Some(ranges) =
 9864                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9865                    {
 9866                        for (buffer, entries) in ranges {
 9867                            linked_ranges.entry(buffer).or_default().extend(entries);
 9868                        }
 9869                    }
 9870                }
 9871            }
 9872
 9873            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9874            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9875            for selection in &mut selections {
 9876                if selection.is_empty() {
 9877                    let old_head = selection.head();
 9878                    let mut new_head =
 9879                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9880                            .to_point(&display_map);
 9881                    if let Some((buffer, line_buffer_range)) = display_map
 9882                        .buffer_snapshot
 9883                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9884                    {
 9885                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9886                        let indent_len = match indent_size.kind {
 9887                            IndentKind::Space => {
 9888                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9889                            }
 9890                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9891                        };
 9892                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9893                            let indent_len = indent_len.get();
 9894                            new_head = cmp::min(
 9895                                new_head,
 9896                                MultiBufferPoint::new(
 9897                                    old_head.row,
 9898                                    ((old_head.column - 1) / indent_len) * indent_len,
 9899                                ),
 9900                            );
 9901                        }
 9902                    }
 9903
 9904                    selection.set_head(new_head, SelectionGoal::None);
 9905                }
 9906            }
 9907
 9908            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9909            this.insert("", window, cx);
 9910            let empty_str: Arc<str> = Arc::from("");
 9911            for (buffer, edits) in linked_ranges {
 9912                let snapshot = buffer.read(cx).snapshot();
 9913                use text::ToPoint as TP;
 9914
 9915                let edits = edits
 9916                    .into_iter()
 9917                    .map(|range| {
 9918                        let end_point = TP::to_point(&range.end, &snapshot);
 9919                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9920
 9921                        if end_point == start_point {
 9922                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9923                                .saturating_sub(1);
 9924                            start_point =
 9925                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9926                        };
 9927
 9928                        (start_point..end_point, empty_str.clone())
 9929                    })
 9930                    .sorted_by_key(|(range, _)| range.start)
 9931                    .collect::<Vec<_>>();
 9932                buffer.update(cx, |this, cx| {
 9933                    this.edit(edits, None, cx);
 9934                })
 9935            }
 9936            this.refresh_edit_prediction(true, false, window, cx);
 9937            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9938        });
 9939    }
 9940
 9941    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9942        if self.read_only(cx) {
 9943            return;
 9944        }
 9945        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9946        self.transact(window, cx, |this, window, cx| {
 9947            this.change_selections(Default::default(), window, cx, |s| {
 9948                s.move_with(|map, selection| {
 9949                    if selection.is_empty() {
 9950                        let cursor = movement::right(map, selection.head());
 9951                        selection.end = cursor;
 9952                        selection.reversed = true;
 9953                        selection.goal = SelectionGoal::None;
 9954                    }
 9955                })
 9956            });
 9957            this.insert("", window, cx);
 9958            this.refresh_edit_prediction(true, false, window, cx);
 9959        });
 9960    }
 9961
 9962    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9963        if self.mode.is_single_line() {
 9964            cx.propagate();
 9965            return;
 9966        }
 9967
 9968        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9969        if self.move_to_prev_snippet_tabstop(window, cx) {
 9970            return;
 9971        }
 9972        self.outdent(&Outdent, window, cx);
 9973    }
 9974
 9975    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9976        if self.mode.is_single_line() {
 9977            cx.propagate();
 9978            return;
 9979        }
 9980
 9981        if self.move_to_next_snippet_tabstop(window, cx) {
 9982            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9983            return;
 9984        }
 9985        if self.read_only(cx) {
 9986            return;
 9987        }
 9988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9989        let mut selections = self.selections.all_adjusted(cx);
 9990        let buffer = self.buffer.read(cx);
 9991        let snapshot = buffer.snapshot(cx);
 9992        let rows_iter = selections.iter().map(|s| s.head().row);
 9993        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9994
 9995        let has_some_cursor_in_whitespace = selections
 9996            .iter()
 9997            .filter(|selection| selection.is_empty())
 9998            .any(|selection| {
 9999                let cursor = selection.head();
10000                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10001                cursor.column < current_indent.len
10002            });
10003
10004        let mut edits = Vec::new();
10005        let mut prev_edited_row = 0;
10006        let mut row_delta = 0;
10007        for selection in &mut selections {
10008            if selection.start.row != prev_edited_row {
10009                row_delta = 0;
10010            }
10011            prev_edited_row = selection.end.row;
10012
10013            // If the selection is non-empty, then increase the indentation of the selected lines.
10014            if !selection.is_empty() {
10015                row_delta =
10016                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10017                continue;
10018            }
10019
10020            let cursor = selection.head();
10021            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10022            if let Some(suggested_indent) =
10023                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10024            {
10025                // Don't do anything if already at suggested indent
10026                // and there is any other cursor which is not
10027                if has_some_cursor_in_whitespace
10028                    && cursor.column == current_indent.len
10029                    && current_indent.len == suggested_indent.len
10030                {
10031                    continue;
10032                }
10033
10034                // Adjust line and move cursor to suggested indent
10035                // if cursor is not at suggested indent
10036                if cursor.column < suggested_indent.len
10037                    && cursor.column <= current_indent.len
10038                    && current_indent.len <= suggested_indent.len
10039                {
10040                    selection.start = Point::new(cursor.row, suggested_indent.len);
10041                    selection.end = selection.start;
10042                    if row_delta == 0 {
10043                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10044                            cursor.row,
10045                            current_indent,
10046                            suggested_indent,
10047                        ));
10048                        row_delta = suggested_indent.len - current_indent.len;
10049                    }
10050                    continue;
10051                }
10052
10053                // If current indent is more than suggested indent
10054                // only move cursor to current indent and skip indent
10055                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10056                    selection.start = Point::new(cursor.row, current_indent.len);
10057                    selection.end = selection.start;
10058                    continue;
10059                }
10060            }
10061
10062            // Otherwise, insert a hard or soft tab.
10063            let settings = buffer.language_settings_at(cursor, cx);
10064            let tab_size = if settings.hard_tabs {
10065                IndentSize::tab()
10066            } else {
10067                let tab_size = settings.tab_size.get();
10068                let indent_remainder = snapshot
10069                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10070                    .flat_map(str::chars)
10071                    .fold(row_delta % tab_size, |counter: u32, c| {
10072                        if c == '\t' {
10073                            0
10074                        } else {
10075                            (counter + 1) % tab_size
10076                        }
10077                    });
10078
10079                let chars_to_next_tab_stop = tab_size - indent_remainder;
10080                IndentSize::spaces(chars_to_next_tab_stop)
10081            };
10082            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10083            selection.end = selection.start;
10084            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10085            row_delta += tab_size.len;
10086        }
10087
10088        self.transact(window, cx, |this, window, cx| {
10089            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10090            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10091            this.refresh_edit_prediction(true, false, window, cx);
10092        });
10093    }
10094
10095    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10096        if self.read_only(cx) {
10097            return;
10098        }
10099        if self.mode.is_single_line() {
10100            cx.propagate();
10101            return;
10102        }
10103
10104        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10105        let mut selections = self.selections.all::<Point>(cx);
10106        let mut prev_edited_row = 0;
10107        let mut row_delta = 0;
10108        let mut edits = Vec::new();
10109        let buffer = self.buffer.read(cx);
10110        let snapshot = buffer.snapshot(cx);
10111        for selection in &mut selections {
10112            if selection.start.row != prev_edited_row {
10113                row_delta = 0;
10114            }
10115            prev_edited_row = selection.end.row;
10116
10117            row_delta =
10118                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10119        }
10120
10121        self.transact(window, cx, |this, window, cx| {
10122            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10123            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10124        });
10125    }
10126
10127    fn indent_selection(
10128        buffer: &MultiBuffer,
10129        snapshot: &MultiBufferSnapshot,
10130        selection: &mut Selection<Point>,
10131        edits: &mut Vec<(Range<Point>, String)>,
10132        delta_for_start_row: u32,
10133        cx: &App,
10134    ) -> u32 {
10135        let settings = buffer.language_settings_at(selection.start, cx);
10136        let tab_size = settings.tab_size.get();
10137        let indent_kind = if settings.hard_tabs {
10138            IndentKind::Tab
10139        } else {
10140            IndentKind::Space
10141        };
10142        let mut start_row = selection.start.row;
10143        let mut end_row = selection.end.row + 1;
10144
10145        // If a selection ends at the beginning of a line, don't indent
10146        // that last line.
10147        if selection.end.column == 0 && selection.end.row > selection.start.row {
10148            end_row -= 1;
10149        }
10150
10151        // Avoid re-indenting a row that has already been indented by a
10152        // previous selection, but still update this selection's column
10153        // to reflect that indentation.
10154        if delta_for_start_row > 0 {
10155            start_row += 1;
10156            selection.start.column += delta_for_start_row;
10157            if selection.end.row == selection.start.row {
10158                selection.end.column += delta_for_start_row;
10159            }
10160        }
10161
10162        let mut delta_for_end_row = 0;
10163        let has_multiple_rows = start_row + 1 != end_row;
10164        for row in start_row..end_row {
10165            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10166            let indent_delta = match (current_indent.kind, indent_kind) {
10167                (IndentKind::Space, IndentKind::Space) => {
10168                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10169                    IndentSize::spaces(columns_to_next_tab_stop)
10170                }
10171                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10172                (_, IndentKind::Tab) => IndentSize::tab(),
10173            };
10174
10175            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10176                0
10177            } else {
10178                selection.start.column
10179            };
10180            let row_start = Point::new(row, start);
10181            edits.push((
10182                row_start..row_start,
10183                indent_delta.chars().collect::<String>(),
10184            ));
10185
10186            // Update this selection's endpoints to reflect the indentation.
10187            if row == selection.start.row {
10188                selection.start.column += indent_delta.len;
10189            }
10190            if row == selection.end.row {
10191                selection.end.column += indent_delta.len;
10192                delta_for_end_row = indent_delta.len;
10193            }
10194        }
10195
10196        if selection.start.row == selection.end.row {
10197            delta_for_start_row + delta_for_end_row
10198        } else {
10199            delta_for_end_row
10200        }
10201    }
10202
10203    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10204        if self.read_only(cx) {
10205            return;
10206        }
10207        if self.mode.is_single_line() {
10208            cx.propagate();
10209            return;
10210        }
10211
10212        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10213        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10214        let selections = self.selections.all::<Point>(cx);
10215        let mut deletion_ranges = Vec::new();
10216        let mut last_outdent = None;
10217        {
10218            let buffer = self.buffer.read(cx);
10219            let snapshot = buffer.snapshot(cx);
10220            for selection in &selections {
10221                let settings = buffer.language_settings_at(selection.start, cx);
10222                let tab_size = settings.tab_size.get();
10223                let mut rows = selection.spanned_rows(false, &display_map);
10224
10225                // Avoid re-outdenting a row that has already been outdented by a
10226                // previous selection.
10227                if let Some(last_row) = last_outdent
10228                    && last_row == rows.start
10229                {
10230                    rows.start = rows.start.next_row();
10231                }
10232                let has_multiple_rows = rows.len() > 1;
10233                for row in rows.iter_rows() {
10234                    let indent_size = snapshot.indent_size_for_line(row);
10235                    if indent_size.len > 0 {
10236                        let deletion_len = match indent_size.kind {
10237                            IndentKind::Space => {
10238                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10239                                if columns_to_prev_tab_stop == 0 {
10240                                    tab_size
10241                                } else {
10242                                    columns_to_prev_tab_stop
10243                                }
10244                            }
10245                            IndentKind::Tab => 1,
10246                        };
10247                        let start = if has_multiple_rows
10248                            || deletion_len > selection.start.column
10249                            || indent_size.len < selection.start.column
10250                        {
10251                            0
10252                        } else {
10253                            selection.start.column - deletion_len
10254                        };
10255                        deletion_ranges.push(
10256                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10257                        );
10258                        last_outdent = Some(row);
10259                    }
10260                }
10261            }
10262        }
10263
10264        self.transact(window, cx, |this, window, cx| {
10265            this.buffer.update(cx, |buffer, cx| {
10266                let empty_str: Arc<str> = Arc::default();
10267                buffer.edit(
10268                    deletion_ranges
10269                        .into_iter()
10270                        .map(|range| (range, empty_str.clone())),
10271                    None,
10272                    cx,
10273                );
10274            });
10275            let selections = this.selections.all::<usize>(cx);
10276            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10277        });
10278    }
10279
10280    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10281        if self.read_only(cx) {
10282            return;
10283        }
10284        if self.mode.is_single_line() {
10285            cx.propagate();
10286            return;
10287        }
10288
10289        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10290        let selections = self
10291            .selections
10292            .all::<usize>(cx)
10293            .into_iter()
10294            .map(|s| s.range());
10295
10296        self.transact(window, cx, |this, window, cx| {
10297            this.buffer.update(cx, |buffer, cx| {
10298                buffer.autoindent_ranges(selections, cx);
10299            });
10300            let selections = this.selections.all::<usize>(cx);
10301            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10302        });
10303    }
10304
10305    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10306        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10307        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10308        let selections = self.selections.all::<Point>(cx);
10309
10310        let mut new_cursors = Vec::new();
10311        let mut edit_ranges = Vec::new();
10312        let mut selections = selections.iter().peekable();
10313        while let Some(selection) = selections.next() {
10314            let mut rows = selection.spanned_rows(false, &display_map);
10315            let goal_display_column = selection.head().to_display_point(&display_map).column();
10316
10317            // Accumulate contiguous regions of rows that we want to delete.
10318            while let Some(next_selection) = selections.peek() {
10319                let next_rows = next_selection.spanned_rows(false, &display_map);
10320                if next_rows.start <= rows.end {
10321                    rows.end = next_rows.end;
10322                    selections.next().unwrap();
10323                } else {
10324                    break;
10325                }
10326            }
10327
10328            let buffer = &display_map.buffer_snapshot;
10329            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10330            let edit_end;
10331            let cursor_buffer_row;
10332            if buffer.max_point().row >= rows.end.0 {
10333                // If there's a line after the range, delete the \n from the end of the row range
10334                // and position the cursor on the next line.
10335                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10336                cursor_buffer_row = rows.end;
10337            } else {
10338                // If there isn't a line after the range, delete the \n from the line before the
10339                // start of the row range and position the cursor there.
10340                edit_start = edit_start.saturating_sub(1);
10341                edit_end = buffer.len();
10342                cursor_buffer_row = rows.start.previous_row();
10343            }
10344
10345            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10346            *cursor.column_mut() =
10347                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10348
10349            new_cursors.push((
10350                selection.id,
10351                buffer.anchor_after(cursor.to_point(&display_map)),
10352            ));
10353            edit_ranges.push(edit_start..edit_end);
10354        }
10355
10356        self.transact(window, cx, |this, window, cx| {
10357            let buffer = this.buffer.update(cx, |buffer, cx| {
10358                let empty_str: Arc<str> = Arc::default();
10359                buffer.edit(
10360                    edit_ranges
10361                        .into_iter()
10362                        .map(|range| (range, empty_str.clone())),
10363                    None,
10364                    cx,
10365                );
10366                buffer.snapshot(cx)
10367            });
10368            let new_selections = new_cursors
10369                .into_iter()
10370                .map(|(id, cursor)| {
10371                    let cursor = cursor.to_point(&buffer);
10372                    Selection {
10373                        id,
10374                        start: cursor,
10375                        end: cursor,
10376                        reversed: false,
10377                        goal: SelectionGoal::None,
10378                    }
10379                })
10380                .collect();
10381
10382            this.change_selections(Default::default(), window, cx, |s| {
10383                s.select(new_selections);
10384            });
10385        });
10386    }
10387
10388    pub fn join_lines_impl(
10389        &mut self,
10390        insert_whitespace: bool,
10391        window: &mut Window,
10392        cx: &mut Context<Self>,
10393    ) {
10394        if self.read_only(cx) {
10395            return;
10396        }
10397        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10398        for selection in self.selections.all::<Point>(cx) {
10399            let start = MultiBufferRow(selection.start.row);
10400            // Treat single line selections as if they include the next line. Otherwise this action
10401            // would do nothing for single line selections individual cursors.
10402            let end = if selection.start.row == selection.end.row {
10403                MultiBufferRow(selection.start.row + 1)
10404            } else {
10405                MultiBufferRow(selection.end.row)
10406            };
10407
10408            if let Some(last_row_range) = row_ranges.last_mut()
10409                && start <= last_row_range.end
10410            {
10411                last_row_range.end = end;
10412                continue;
10413            }
10414            row_ranges.push(start..end);
10415        }
10416
10417        let snapshot = self.buffer.read(cx).snapshot(cx);
10418        let mut cursor_positions = Vec::new();
10419        for row_range in &row_ranges {
10420            let anchor = snapshot.anchor_before(Point::new(
10421                row_range.end.previous_row().0,
10422                snapshot.line_len(row_range.end.previous_row()),
10423            ));
10424            cursor_positions.push(anchor..anchor);
10425        }
10426
10427        self.transact(window, cx, |this, window, cx| {
10428            for row_range in row_ranges.into_iter().rev() {
10429                for row in row_range.iter_rows().rev() {
10430                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10431                    let next_line_row = row.next_row();
10432                    let indent = snapshot.indent_size_for_line(next_line_row);
10433                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10434
10435                    let replace =
10436                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10437                            " "
10438                        } else {
10439                            ""
10440                        };
10441
10442                    this.buffer.update(cx, |buffer, cx| {
10443                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10444                    });
10445                }
10446            }
10447
10448            this.change_selections(Default::default(), window, cx, |s| {
10449                s.select_anchor_ranges(cursor_positions)
10450            });
10451        });
10452    }
10453
10454    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10455        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10456        self.join_lines_impl(true, window, cx);
10457    }
10458
10459    pub fn sort_lines_case_sensitive(
10460        &mut self,
10461        _: &SortLinesCaseSensitive,
10462        window: &mut Window,
10463        cx: &mut Context<Self>,
10464    ) {
10465        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10466    }
10467
10468    pub fn sort_lines_by_length(
10469        &mut self,
10470        _: &SortLinesByLength,
10471        window: &mut Window,
10472        cx: &mut Context<Self>,
10473    ) {
10474        self.manipulate_immutable_lines(window, cx, |lines| {
10475            lines.sort_by_key(|&line| line.chars().count())
10476        })
10477    }
10478
10479    pub fn sort_lines_case_insensitive(
10480        &mut self,
10481        _: &SortLinesCaseInsensitive,
10482        window: &mut Window,
10483        cx: &mut Context<Self>,
10484    ) {
10485        self.manipulate_immutable_lines(window, cx, |lines| {
10486            lines.sort_by_key(|line| line.to_lowercase())
10487        })
10488    }
10489
10490    pub fn unique_lines_case_insensitive(
10491        &mut self,
10492        _: &UniqueLinesCaseInsensitive,
10493        window: &mut Window,
10494        cx: &mut Context<Self>,
10495    ) {
10496        self.manipulate_immutable_lines(window, cx, |lines| {
10497            let mut seen = HashSet::default();
10498            lines.retain(|line| seen.insert(line.to_lowercase()));
10499        })
10500    }
10501
10502    pub fn unique_lines_case_sensitive(
10503        &mut self,
10504        _: &UniqueLinesCaseSensitive,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) {
10508        self.manipulate_immutable_lines(window, cx, |lines| {
10509            let mut seen = HashSet::default();
10510            lines.retain(|line| seen.insert(*line));
10511        })
10512    }
10513
10514    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10515        let snapshot = self.buffer.read(cx).snapshot(cx);
10516        for selection in self.selections.disjoint_anchors().iter() {
10517            if snapshot
10518                .language_at(selection.start)
10519                .and_then(|lang| lang.config().wrap_characters.as_ref())
10520                .is_some()
10521            {
10522                return true;
10523            }
10524        }
10525        false
10526    }
10527
10528    fn wrap_selections_in_tag(
10529        &mut self,
10530        _: &WrapSelectionsInTag,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10535
10536        let snapshot = self.buffer.read(cx).snapshot(cx);
10537
10538        let mut edits = Vec::new();
10539        let mut boundaries = Vec::new();
10540
10541        for selection in self.selections.all::<Point>(cx).iter() {
10542            let Some(wrap_config) = snapshot
10543                .language_at(selection.start)
10544                .and_then(|lang| lang.config().wrap_characters.clone())
10545            else {
10546                continue;
10547            };
10548
10549            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10550            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10551
10552            let start_before = snapshot.anchor_before(selection.start);
10553            let end_after = snapshot.anchor_after(selection.end);
10554
10555            edits.push((start_before..start_before, open_tag));
10556            edits.push((end_after..end_after, close_tag));
10557
10558            boundaries.push((
10559                start_before,
10560                end_after,
10561                wrap_config.start_prefix.len(),
10562                wrap_config.end_suffix.len(),
10563            ));
10564        }
10565
10566        if edits.is_empty() {
10567            return;
10568        }
10569
10570        self.transact(window, cx, |this, window, cx| {
10571            let buffer = this.buffer.update(cx, |buffer, cx| {
10572                buffer.edit(edits, None, cx);
10573                buffer.snapshot(cx)
10574            });
10575
10576            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10577            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10578                boundaries.into_iter()
10579            {
10580                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10581                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10582                new_selections.push(open_offset..open_offset);
10583                new_selections.push(close_offset..close_offset);
10584            }
10585
10586            this.change_selections(Default::default(), window, cx, |s| {
10587                s.select_ranges(new_selections);
10588            });
10589
10590            this.request_autoscroll(Autoscroll::fit(), cx);
10591        });
10592    }
10593
10594    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10595        let Some(project) = self.project.clone() else {
10596            return;
10597        };
10598        self.reload(project, window, cx)
10599            .detach_and_notify_err(window, cx);
10600    }
10601
10602    pub fn restore_file(
10603        &mut self,
10604        _: &::git::RestoreFile,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10609        let mut buffer_ids = HashSet::default();
10610        let snapshot = self.buffer().read(cx).snapshot(cx);
10611        for selection in self.selections.all::<usize>(cx) {
10612            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10613        }
10614
10615        let buffer = self.buffer().read(cx);
10616        let ranges = buffer_ids
10617            .into_iter()
10618            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10619            .collect::<Vec<_>>();
10620
10621        self.restore_hunks_in_ranges(ranges, window, cx);
10622    }
10623
10624    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10625        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10626        let selections = self
10627            .selections
10628            .all(cx)
10629            .into_iter()
10630            .map(|s| s.range())
10631            .collect();
10632        self.restore_hunks_in_ranges(selections, window, cx);
10633    }
10634
10635    pub fn restore_hunks_in_ranges(
10636        &mut self,
10637        ranges: Vec<Range<Point>>,
10638        window: &mut Window,
10639        cx: &mut Context<Editor>,
10640    ) {
10641        let mut revert_changes = HashMap::default();
10642        let chunk_by = self
10643            .snapshot(window, cx)
10644            .hunks_for_ranges(ranges)
10645            .into_iter()
10646            .chunk_by(|hunk| hunk.buffer_id);
10647        for (buffer_id, hunks) in &chunk_by {
10648            let hunks = hunks.collect::<Vec<_>>();
10649            for hunk in &hunks {
10650                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10651            }
10652            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10653        }
10654        drop(chunk_by);
10655        if !revert_changes.is_empty() {
10656            self.transact(window, cx, |editor, window, cx| {
10657                editor.restore(revert_changes, window, cx);
10658            });
10659        }
10660    }
10661
10662    pub fn open_active_item_in_terminal(
10663        &mut self,
10664        _: &OpenInTerminal,
10665        window: &mut Window,
10666        cx: &mut Context<Self>,
10667    ) {
10668        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10669            let project_path = buffer.read(cx).project_path(cx)?;
10670            let project = self.project()?.read(cx);
10671            let entry = project.entry_for_path(&project_path, cx)?;
10672            let parent = match &entry.canonical_path {
10673                Some(canonical_path) => canonical_path.to_path_buf(),
10674                None => project.absolute_path(&project_path, cx)?,
10675            }
10676            .parent()?
10677            .to_path_buf();
10678            Some(parent)
10679        }) {
10680            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10681        }
10682    }
10683
10684    fn set_breakpoint_context_menu(
10685        &mut self,
10686        display_row: DisplayRow,
10687        position: Option<Anchor>,
10688        clicked_point: gpui::Point<Pixels>,
10689        window: &mut Window,
10690        cx: &mut Context<Self>,
10691    ) {
10692        let source = self
10693            .buffer
10694            .read(cx)
10695            .snapshot(cx)
10696            .anchor_before(Point::new(display_row.0, 0u32));
10697
10698        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10699
10700        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10701            self,
10702            source,
10703            clicked_point,
10704            context_menu,
10705            window,
10706            cx,
10707        );
10708    }
10709
10710    fn add_edit_breakpoint_block(
10711        &mut self,
10712        anchor: Anchor,
10713        breakpoint: &Breakpoint,
10714        edit_action: BreakpointPromptEditAction,
10715        window: &mut Window,
10716        cx: &mut Context<Self>,
10717    ) {
10718        let weak_editor = cx.weak_entity();
10719        let bp_prompt = cx.new(|cx| {
10720            BreakpointPromptEditor::new(
10721                weak_editor,
10722                anchor,
10723                breakpoint.clone(),
10724                edit_action,
10725                window,
10726                cx,
10727            )
10728        });
10729
10730        let height = bp_prompt.update(cx, |this, cx| {
10731            this.prompt
10732                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10733        });
10734        let cloned_prompt = bp_prompt.clone();
10735        let blocks = vec![BlockProperties {
10736            style: BlockStyle::Sticky,
10737            placement: BlockPlacement::Above(anchor),
10738            height: Some(height),
10739            render: Arc::new(move |cx| {
10740                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10741                cloned_prompt.clone().into_any_element()
10742            }),
10743            priority: 0,
10744        }];
10745
10746        let focus_handle = bp_prompt.focus_handle(cx);
10747        window.focus(&focus_handle);
10748
10749        let block_ids = self.insert_blocks(blocks, None, cx);
10750        bp_prompt.update(cx, |prompt, _| {
10751            prompt.add_block_ids(block_ids);
10752        });
10753    }
10754
10755    pub(crate) fn breakpoint_at_row(
10756        &self,
10757        row: u32,
10758        window: &mut Window,
10759        cx: &mut Context<Self>,
10760    ) -> Option<(Anchor, Breakpoint)> {
10761        let snapshot = self.snapshot(window, cx);
10762        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10763
10764        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10765    }
10766
10767    pub(crate) fn breakpoint_at_anchor(
10768        &self,
10769        breakpoint_position: Anchor,
10770        snapshot: &EditorSnapshot,
10771        cx: &mut Context<Self>,
10772    ) -> Option<(Anchor, Breakpoint)> {
10773        let buffer = self
10774            .buffer
10775            .read(cx)
10776            .buffer_for_anchor(breakpoint_position, cx)?;
10777
10778        let enclosing_excerpt = breakpoint_position.excerpt_id;
10779        let buffer_snapshot = buffer.read(cx).snapshot();
10780
10781        let row = buffer_snapshot
10782            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10783            .row;
10784
10785        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10786        let anchor_end = snapshot
10787            .buffer_snapshot
10788            .anchor_after(Point::new(row, line_len));
10789
10790        self.breakpoint_store
10791            .as_ref()?
10792            .read_with(cx, |breakpoint_store, cx| {
10793                breakpoint_store
10794                    .breakpoints(
10795                        &buffer,
10796                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10797                        &buffer_snapshot,
10798                        cx,
10799                    )
10800                    .next()
10801                    .and_then(|(bp, _)| {
10802                        let breakpoint_row = buffer_snapshot
10803                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10804                            .row;
10805
10806                        if breakpoint_row == row {
10807                            snapshot
10808                                .buffer_snapshot
10809                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10810                                .map(|position| (position, bp.bp.clone()))
10811                        } else {
10812                            None
10813                        }
10814                    })
10815            })
10816    }
10817
10818    pub fn edit_log_breakpoint(
10819        &mut self,
10820        _: &EditLogBreakpoint,
10821        window: &mut Window,
10822        cx: &mut Context<Self>,
10823    ) {
10824        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10825            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10826                message: None,
10827                state: BreakpointState::Enabled,
10828                condition: None,
10829                hit_condition: None,
10830            });
10831
10832            self.add_edit_breakpoint_block(
10833                anchor,
10834                &breakpoint,
10835                BreakpointPromptEditAction::Log,
10836                window,
10837                cx,
10838            );
10839        }
10840    }
10841
10842    fn breakpoints_at_cursors(
10843        &self,
10844        window: &mut Window,
10845        cx: &mut Context<Self>,
10846    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10847        let snapshot = self.snapshot(window, cx);
10848        let cursors = self
10849            .selections
10850            .disjoint_anchors()
10851            .iter()
10852            .map(|selection| {
10853                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10854
10855                let breakpoint_position = self
10856                    .breakpoint_at_row(cursor_position.row, window, cx)
10857                    .map(|bp| bp.0)
10858                    .unwrap_or_else(|| {
10859                        snapshot
10860                            .display_snapshot
10861                            .buffer_snapshot
10862                            .anchor_after(Point::new(cursor_position.row, 0))
10863                    });
10864
10865                let breakpoint = self
10866                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10867                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10868
10869                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10870            })
10871            // 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.
10872            .collect::<HashMap<Anchor, _>>();
10873
10874        cursors.into_iter().collect()
10875    }
10876
10877    pub fn enable_breakpoint(
10878        &mut self,
10879        _: &crate::actions::EnableBreakpoint,
10880        window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10884            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10885                continue;
10886            };
10887            self.edit_breakpoint_at_anchor(
10888                anchor,
10889                breakpoint,
10890                BreakpointEditAction::InvertState,
10891                cx,
10892            );
10893        }
10894    }
10895
10896    pub fn disable_breakpoint(
10897        &mut self,
10898        _: &crate::actions::DisableBreakpoint,
10899        window: &mut Window,
10900        cx: &mut Context<Self>,
10901    ) {
10902        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10903            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10904                continue;
10905            };
10906            self.edit_breakpoint_at_anchor(
10907                anchor,
10908                breakpoint,
10909                BreakpointEditAction::InvertState,
10910                cx,
10911            );
10912        }
10913    }
10914
10915    pub fn toggle_breakpoint(
10916        &mut self,
10917        _: &crate::actions::ToggleBreakpoint,
10918        window: &mut Window,
10919        cx: &mut Context<Self>,
10920    ) {
10921        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10922            if let Some(breakpoint) = breakpoint {
10923                self.edit_breakpoint_at_anchor(
10924                    anchor,
10925                    breakpoint,
10926                    BreakpointEditAction::Toggle,
10927                    cx,
10928                );
10929            } else {
10930                self.edit_breakpoint_at_anchor(
10931                    anchor,
10932                    Breakpoint::new_standard(),
10933                    BreakpointEditAction::Toggle,
10934                    cx,
10935                );
10936            }
10937        }
10938    }
10939
10940    pub fn edit_breakpoint_at_anchor(
10941        &mut self,
10942        breakpoint_position: Anchor,
10943        breakpoint: Breakpoint,
10944        edit_action: BreakpointEditAction,
10945        cx: &mut Context<Self>,
10946    ) {
10947        let Some(breakpoint_store) = &self.breakpoint_store else {
10948            return;
10949        };
10950
10951        let Some(buffer) = self
10952            .buffer
10953            .read(cx)
10954            .buffer_for_anchor(breakpoint_position, cx)
10955        else {
10956            return;
10957        };
10958
10959        breakpoint_store.update(cx, |breakpoint_store, cx| {
10960            breakpoint_store.toggle_breakpoint(
10961                buffer,
10962                BreakpointWithPosition {
10963                    position: breakpoint_position.text_anchor,
10964                    bp: breakpoint,
10965                },
10966                edit_action,
10967                cx,
10968            );
10969        });
10970
10971        cx.notify();
10972    }
10973
10974    #[cfg(any(test, feature = "test-support"))]
10975    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10976        self.breakpoint_store.clone()
10977    }
10978
10979    pub fn prepare_restore_change(
10980        &self,
10981        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10982        hunk: &MultiBufferDiffHunk,
10983        cx: &mut App,
10984    ) -> Option<()> {
10985        if hunk.is_created_file() {
10986            return None;
10987        }
10988        let buffer = self.buffer.read(cx);
10989        let diff = buffer.diff_for(hunk.buffer_id)?;
10990        let buffer = buffer.buffer(hunk.buffer_id)?;
10991        let buffer = buffer.read(cx);
10992        let original_text = diff
10993            .read(cx)
10994            .base_text()
10995            .as_rope()
10996            .slice(hunk.diff_base_byte_range.clone());
10997        let buffer_snapshot = buffer.snapshot();
10998        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10999        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11000            probe
11001                .0
11002                .start
11003                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11004                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11005        }) {
11006            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11007            Some(())
11008        } else {
11009            None
11010        }
11011    }
11012
11013    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11014        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11015    }
11016
11017    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11018        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11019    }
11020
11021    fn manipulate_lines<M>(
11022        &mut self,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025        mut manipulate: M,
11026    ) where
11027        M: FnMut(&str) -> LineManipulationResult,
11028    {
11029        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11030
11031        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11032        let buffer = self.buffer.read(cx).snapshot(cx);
11033
11034        let mut edits = Vec::new();
11035
11036        let selections = self.selections.all::<Point>(cx);
11037        let mut selections = selections.iter().peekable();
11038        let mut contiguous_row_selections = Vec::new();
11039        let mut new_selections = Vec::new();
11040        let mut added_lines = 0;
11041        let mut removed_lines = 0;
11042
11043        while let Some(selection) = selections.next() {
11044            let (start_row, end_row) = consume_contiguous_rows(
11045                &mut contiguous_row_selections,
11046                selection,
11047                &display_map,
11048                &mut selections,
11049            );
11050
11051            let start_point = Point::new(start_row.0, 0);
11052            let end_point = Point::new(
11053                end_row.previous_row().0,
11054                buffer.line_len(end_row.previous_row()),
11055            );
11056            let text = buffer
11057                .text_for_range(start_point..end_point)
11058                .collect::<String>();
11059
11060            let LineManipulationResult {
11061                new_text,
11062                line_count_before,
11063                line_count_after,
11064            } = manipulate(&text);
11065
11066            edits.push((start_point..end_point, new_text));
11067
11068            // Selections must change based on added and removed line count
11069            let start_row =
11070                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11071            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11072            new_selections.push(Selection {
11073                id: selection.id,
11074                start: start_row,
11075                end: end_row,
11076                goal: SelectionGoal::None,
11077                reversed: selection.reversed,
11078            });
11079
11080            if line_count_after > line_count_before {
11081                added_lines += line_count_after - line_count_before;
11082            } else if line_count_before > line_count_after {
11083                removed_lines += line_count_before - line_count_after;
11084            }
11085        }
11086
11087        self.transact(window, cx, |this, window, cx| {
11088            let buffer = this.buffer.update(cx, |buffer, cx| {
11089                buffer.edit(edits, None, cx);
11090                buffer.snapshot(cx)
11091            });
11092
11093            // Recalculate offsets on newly edited buffer
11094            let new_selections = new_selections
11095                .iter()
11096                .map(|s| {
11097                    let start_point = Point::new(s.start.0, 0);
11098                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11099                    Selection {
11100                        id: s.id,
11101                        start: buffer.point_to_offset(start_point),
11102                        end: buffer.point_to_offset(end_point),
11103                        goal: s.goal,
11104                        reversed: s.reversed,
11105                    }
11106                })
11107                .collect();
11108
11109            this.change_selections(Default::default(), window, cx, |s| {
11110                s.select(new_selections);
11111            });
11112
11113            this.request_autoscroll(Autoscroll::fit(), cx);
11114        });
11115    }
11116
11117    fn manipulate_immutable_lines<Fn>(
11118        &mut self,
11119        window: &mut Window,
11120        cx: &mut Context<Self>,
11121        mut callback: Fn,
11122    ) where
11123        Fn: FnMut(&mut Vec<&str>),
11124    {
11125        self.manipulate_lines(window, cx, |text| {
11126            let mut lines: Vec<&str> = text.split('\n').collect();
11127            let line_count_before = lines.len();
11128
11129            callback(&mut lines);
11130
11131            LineManipulationResult {
11132                new_text: lines.join("\n"),
11133                line_count_before,
11134                line_count_after: lines.len(),
11135            }
11136        });
11137    }
11138
11139    fn manipulate_mutable_lines<Fn>(
11140        &mut self,
11141        window: &mut Window,
11142        cx: &mut Context<Self>,
11143        mut callback: Fn,
11144    ) where
11145        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11146    {
11147        self.manipulate_lines(window, cx, |text| {
11148            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11149            let line_count_before = lines.len();
11150
11151            callback(&mut lines);
11152
11153            LineManipulationResult {
11154                new_text: lines.join("\n"),
11155                line_count_before,
11156                line_count_after: lines.len(),
11157            }
11158        });
11159    }
11160
11161    pub fn convert_indentation_to_spaces(
11162        &mut self,
11163        _: &ConvertIndentationToSpaces,
11164        window: &mut Window,
11165        cx: &mut Context<Self>,
11166    ) {
11167        let settings = self.buffer.read(cx).language_settings(cx);
11168        let tab_size = settings.tab_size.get() as usize;
11169
11170        self.manipulate_mutable_lines(window, cx, |lines| {
11171            // Allocates a reasonably sized scratch buffer once for the whole loop
11172            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11173            // Avoids recomputing spaces that could be inserted many times
11174            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11175                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11176                .collect();
11177
11178            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11179                let mut chars = line.as_ref().chars();
11180                let mut col = 0;
11181                let mut changed = false;
11182
11183                for ch in chars.by_ref() {
11184                    match ch {
11185                        ' ' => {
11186                            reindented_line.push(' ');
11187                            col += 1;
11188                        }
11189                        '\t' => {
11190                            // \t are converted to spaces depending on the current column
11191                            let spaces_len = tab_size - (col % tab_size);
11192                            reindented_line.extend(&space_cache[spaces_len - 1]);
11193                            col += spaces_len;
11194                            changed = true;
11195                        }
11196                        _ => {
11197                            // If we dont append before break, the character is consumed
11198                            reindented_line.push(ch);
11199                            break;
11200                        }
11201                    }
11202                }
11203
11204                if !changed {
11205                    reindented_line.clear();
11206                    continue;
11207                }
11208                // Append the rest of the line and replace old reference with new one
11209                reindented_line.extend(chars);
11210                *line = Cow::Owned(reindented_line.clone());
11211                reindented_line.clear();
11212            }
11213        });
11214    }
11215
11216    pub fn convert_indentation_to_tabs(
11217        &mut self,
11218        _: &ConvertIndentationToTabs,
11219        window: &mut Window,
11220        cx: &mut Context<Self>,
11221    ) {
11222        let settings = self.buffer.read(cx).language_settings(cx);
11223        let tab_size = settings.tab_size.get() as usize;
11224
11225        self.manipulate_mutable_lines(window, cx, |lines| {
11226            // Allocates a reasonably sized buffer once for the whole loop
11227            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11228            // Avoids recomputing spaces that could be inserted many times
11229            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11230                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11231                .collect();
11232
11233            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11234                let mut chars = line.chars();
11235                let mut spaces_count = 0;
11236                let mut first_non_indent_char = None;
11237                let mut changed = false;
11238
11239                for ch in chars.by_ref() {
11240                    match ch {
11241                        ' ' => {
11242                            // Keep track of spaces. Append \t when we reach tab_size
11243                            spaces_count += 1;
11244                            changed = true;
11245                            if spaces_count == tab_size {
11246                                reindented_line.push('\t');
11247                                spaces_count = 0;
11248                            }
11249                        }
11250                        '\t' => {
11251                            reindented_line.push('\t');
11252                            spaces_count = 0;
11253                        }
11254                        _ => {
11255                            // Dont append it yet, we might have remaining spaces
11256                            first_non_indent_char = Some(ch);
11257                            break;
11258                        }
11259                    }
11260                }
11261
11262                if !changed {
11263                    reindented_line.clear();
11264                    continue;
11265                }
11266                // Remaining spaces that didn't make a full tab stop
11267                if spaces_count > 0 {
11268                    reindented_line.extend(&space_cache[spaces_count - 1]);
11269                }
11270                // If we consume an extra character that was not indentation, add it back
11271                if let Some(extra_char) = first_non_indent_char {
11272                    reindented_line.push(extra_char);
11273                }
11274                // Append the rest of the line and replace old reference with new one
11275                reindented_line.extend(chars);
11276                *line = Cow::Owned(reindented_line.clone());
11277                reindented_line.clear();
11278            }
11279        });
11280    }
11281
11282    pub fn convert_to_upper_case(
11283        &mut self,
11284        _: &ConvertToUpperCase,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287    ) {
11288        self.manipulate_text(window, cx, |text| text.to_uppercase())
11289    }
11290
11291    pub fn convert_to_lower_case(
11292        &mut self,
11293        _: &ConvertToLowerCase,
11294        window: &mut Window,
11295        cx: &mut Context<Self>,
11296    ) {
11297        self.manipulate_text(window, cx, |text| text.to_lowercase())
11298    }
11299
11300    pub fn convert_to_title_case(
11301        &mut self,
11302        _: &ConvertToTitleCase,
11303        window: &mut Window,
11304        cx: &mut Context<Self>,
11305    ) {
11306        self.manipulate_text(window, cx, |text| {
11307            text.split('\n')
11308                .map(|line| line.to_case(Case::Title))
11309                .join("\n")
11310        })
11311    }
11312
11313    pub fn convert_to_snake_case(
11314        &mut self,
11315        _: &ConvertToSnakeCase,
11316        window: &mut Window,
11317        cx: &mut Context<Self>,
11318    ) {
11319        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11320    }
11321
11322    pub fn convert_to_kebab_case(
11323        &mut self,
11324        _: &ConvertToKebabCase,
11325        window: &mut Window,
11326        cx: &mut Context<Self>,
11327    ) {
11328        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11329    }
11330
11331    pub fn convert_to_upper_camel_case(
11332        &mut self,
11333        _: &ConvertToUpperCamelCase,
11334        window: &mut Window,
11335        cx: &mut Context<Self>,
11336    ) {
11337        self.manipulate_text(window, cx, |text| {
11338            text.split('\n')
11339                .map(|line| line.to_case(Case::UpperCamel))
11340                .join("\n")
11341        })
11342    }
11343
11344    pub fn convert_to_lower_camel_case(
11345        &mut self,
11346        _: &ConvertToLowerCamelCase,
11347        window: &mut Window,
11348        cx: &mut Context<Self>,
11349    ) {
11350        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11351    }
11352
11353    pub fn convert_to_opposite_case(
11354        &mut self,
11355        _: &ConvertToOppositeCase,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        self.manipulate_text(window, cx, |text| {
11360            text.chars()
11361                .fold(String::with_capacity(text.len()), |mut t, c| {
11362                    if c.is_uppercase() {
11363                        t.extend(c.to_lowercase());
11364                    } else {
11365                        t.extend(c.to_uppercase());
11366                    }
11367                    t
11368                })
11369        })
11370    }
11371
11372    pub fn convert_to_sentence_case(
11373        &mut self,
11374        _: &ConvertToSentenceCase,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11379    }
11380
11381    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11382        self.manipulate_text(window, cx, |text| {
11383            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11384            if has_upper_case_characters {
11385                text.to_lowercase()
11386            } else {
11387                text.to_uppercase()
11388            }
11389        })
11390    }
11391
11392    pub fn convert_to_rot13(
11393        &mut self,
11394        _: &ConvertToRot13,
11395        window: &mut Window,
11396        cx: &mut Context<Self>,
11397    ) {
11398        self.manipulate_text(window, cx, |text| {
11399            text.chars()
11400                .map(|c| match c {
11401                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11402                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11403                    _ => c,
11404                })
11405                .collect()
11406        })
11407    }
11408
11409    pub fn convert_to_rot47(
11410        &mut self,
11411        _: &ConvertToRot47,
11412        window: &mut Window,
11413        cx: &mut Context<Self>,
11414    ) {
11415        self.manipulate_text(window, cx, |text| {
11416            text.chars()
11417                .map(|c| {
11418                    let code_point = c as u32;
11419                    if code_point >= 33 && code_point <= 126 {
11420                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11421                    }
11422                    c
11423                })
11424                .collect()
11425        })
11426    }
11427
11428    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11429    where
11430        Fn: FnMut(&str) -> String,
11431    {
11432        let buffer = self.buffer.read(cx).snapshot(cx);
11433
11434        let mut new_selections = Vec::new();
11435        let mut edits = Vec::new();
11436        let mut selection_adjustment = 0i32;
11437
11438        for selection in self.selections.all_adjusted(cx) {
11439            let selection_is_empty = selection.is_empty();
11440
11441            let (start, end) = if selection_is_empty {
11442                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11443                (word_range.start, word_range.end)
11444            } else {
11445                (
11446                    buffer.point_to_offset(selection.start),
11447                    buffer.point_to_offset(selection.end),
11448                )
11449            };
11450
11451            let text = buffer.text_for_range(start..end).collect::<String>();
11452            let old_length = text.len() as i32;
11453            let text = callback(&text);
11454
11455            new_selections.push(Selection {
11456                start: (start as i32 - selection_adjustment) as usize,
11457                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11458                goal: SelectionGoal::None,
11459                id: selection.id,
11460                reversed: selection.reversed,
11461            });
11462
11463            selection_adjustment += old_length - text.len() as i32;
11464
11465            edits.push((start..end, text));
11466        }
11467
11468        self.transact(window, cx, |this, window, cx| {
11469            this.buffer.update(cx, |buffer, cx| {
11470                buffer.edit(edits, None, cx);
11471            });
11472
11473            this.change_selections(Default::default(), window, cx, |s| {
11474                s.select(new_selections);
11475            });
11476
11477            this.request_autoscroll(Autoscroll::fit(), cx);
11478        });
11479    }
11480
11481    pub fn move_selection_on_drop(
11482        &mut self,
11483        selection: &Selection<Anchor>,
11484        target: DisplayPoint,
11485        is_cut: bool,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11490        let buffer = &display_map.buffer_snapshot;
11491        let mut edits = Vec::new();
11492        let insert_point = display_map
11493            .clip_point(target, Bias::Left)
11494            .to_point(&display_map);
11495        let text = buffer
11496            .text_for_range(selection.start..selection.end)
11497            .collect::<String>();
11498        if is_cut {
11499            edits.push(((selection.start..selection.end), String::new()));
11500        }
11501        let insert_anchor = buffer.anchor_before(insert_point);
11502        edits.push(((insert_anchor..insert_anchor), text));
11503        let last_edit_start = insert_anchor.bias_left(buffer);
11504        let last_edit_end = insert_anchor.bias_right(buffer);
11505        self.transact(window, cx, |this, window, cx| {
11506            this.buffer.update(cx, |buffer, cx| {
11507                buffer.edit(edits, None, cx);
11508            });
11509            this.change_selections(Default::default(), window, cx, |s| {
11510                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11511            });
11512        });
11513    }
11514
11515    pub fn clear_selection_drag_state(&mut self) {
11516        self.selection_drag_state = SelectionDragState::None;
11517    }
11518
11519    pub fn duplicate(
11520        &mut self,
11521        upwards: bool,
11522        whole_lines: bool,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11527
11528        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11529        let buffer = &display_map.buffer_snapshot;
11530        let selections = self.selections.all::<Point>(cx);
11531
11532        let mut edits = Vec::new();
11533        let mut selections_iter = selections.iter().peekable();
11534        while let Some(selection) = selections_iter.next() {
11535            let mut rows = selection.spanned_rows(false, &display_map);
11536            // duplicate line-wise
11537            if whole_lines || selection.start == selection.end {
11538                // Avoid duplicating the same lines twice.
11539                while let Some(next_selection) = selections_iter.peek() {
11540                    let next_rows = next_selection.spanned_rows(false, &display_map);
11541                    if next_rows.start < rows.end {
11542                        rows.end = next_rows.end;
11543                        selections_iter.next().unwrap();
11544                    } else {
11545                        break;
11546                    }
11547                }
11548
11549                // Copy the text from the selected row region and splice it either at the start
11550                // or end of the region.
11551                let start = Point::new(rows.start.0, 0);
11552                let end = Point::new(
11553                    rows.end.previous_row().0,
11554                    buffer.line_len(rows.end.previous_row()),
11555                );
11556                let text = buffer
11557                    .text_for_range(start..end)
11558                    .chain(Some("\n"))
11559                    .collect::<String>();
11560                let insert_location = if upwards {
11561                    Point::new(rows.end.0, 0)
11562                } else {
11563                    start
11564                };
11565                edits.push((insert_location..insert_location, text));
11566            } else {
11567                // duplicate character-wise
11568                let start = selection.start;
11569                let end = selection.end;
11570                let text = buffer.text_for_range(start..end).collect::<String>();
11571                edits.push((selection.end..selection.end, text));
11572            }
11573        }
11574
11575        self.transact(window, cx, |this, _, cx| {
11576            this.buffer.update(cx, |buffer, cx| {
11577                buffer.edit(edits, None, cx);
11578            });
11579
11580            this.request_autoscroll(Autoscroll::fit(), cx);
11581        });
11582    }
11583
11584    pub fn duplicate_line_up(
11585        &mut self,
11586        _: &DuplicateLineUp,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        self.duplicate(true, true, window, cx);
11591    }
11592
11593    pub fn duplicate_line_down(
11594        &mut self,
11595        _: &DuplicateLineDown,
11596        window: &mut Window,
11597        cx: &mut Context<Self>,
11598    ) {
11599        self.duplicate(false, true, window, cx);
11600    }
11601
11602    pub fn duplicate_selection(
11603        &mut self,
11604        _: &DuplicateSelection,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        self.duplicate(false, false, window, cx);
11609    }
11610
11611    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11612        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11613        if self.mode.is_single_line() {
11614            cx.propagate();
11615            return;
11616        }
11617
11618        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11619        let buffer = self.buffer.read(cx).snapshot(cx);
11620
11621        let mut edits = Vec::new();
11622        let mut unfold_ranges = Vec::new();
11623        let mut refold_creases = Vec::new();
11624
11625        let selections = self.selections.all::<Point>(cx);
11626        let mut selections = selections.iter().peekable();
11627        let mut contiguous_row_selections = Vec::new();
11628        let mut new_selections = Vec::new();
11629
11630        while let Some(selection) = selections.next() {
11631            // Find all the selections that span a contiguous row range
11632            let (start_row, end_row) = consume_contiguous_rows(
11633                &mut contiguous_row_selections,
11634                selection,
11635                &display_map,
11636                &mut selections,
11637            );
11638
11639            // Move the text spanned by the row range to be before the line preceding the row range
11640            if start_row.0 > 0 {
11641                let range_to_move = Point::new(
11642                    start_row.previous_row().0,
11643                    buffer.line_len(start_row.previous_row()),
11644                )
11645                    ..Point::new(
11646                        end_row.previous_row().0,
11647                        buffer.line_len(end_row.previous_row()),
11648                    );
11649                let insertion_point = display_map
11650                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11651                    .0;
11652
11653                // Don't move lines across excerpts
11654                if buffer
11655                    .excerpt_containing(insertion_point..range_to_move.end)
11656                    .is_some()
11657                {
11658                    let text = buffer
11659                        .text_for_range(range_to_move.clone())
11660                        .flat_map(|s| s.chars())
11661                        .skip(1)
11662                        .chain(['\n'])
11663                        .collect::<String>();
11664
11665                    edits.push((
11666                        buffer.anchor_after(range_to_move.start)
11667                            ..buffer.anchor_before(range_to_move.end),
11668                        String::new(),
11669                    ));
11670                    let insertion_anchor = buffer.anchor_after(insertion_point);
11671                    edits.push((insertion_anchor..insertion_anchor, text));
11672
11673                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11674
11675                    // Move selections up
11676                    new_selections.extend(contiguous_row_selections.drain(..).map(
11677                        |mut selection| {
11678                            selection.start.row -= row_delta;
11679                            selection.end.row -= row_delta;
11680                            selection
11681                        },
11682                    ));
11683
11684                    // Move folds up
11685                    unfold_ranges.push(range_to_move.clone());
11686                    for fold in display_map.folds_in_range(
11687                        buffer.anchor_before(range_to_move.start)
11688                            ..buffer.anchor_after(range_to_move.end),
11689                    ) {
11690                        let mut start = fold.range.start.to_point(&buffer);
11691                        let mut end = fold.range.end.to_point(&buffer);
11692                        start.row -= row_delta;
11693                        end.row -= row_delta;
11694                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11695                    }
11696                }
11697            }
11698
11699            // If we didn't move line(s), preserve the existing selections
11700            new_selections.append(&mut contiguous_row_selections);
11701        }
11702
11703        self.transact(window, cx, |this, window, cx| {
11704            this.unfold_ranges(&unfold_ranges, true, true, cx);
11705            this.buffer.update(cx, |buffer, cx| {
11706                for (range, text) in edits {
11707                    buffer.edit([(range, text)], None, cx);
11708                }
11709            });
11710            this.fold_creases(refold_creases, true, window, cx);
11711            this.change_selections(Default::default(), window, cx, |s| {
11712                s.select(new_selections);
11713            })
11714        });
11715    }
11716
11717    pub fn move_line_down(
11718        &mut self,
11719        _: &MoveLineDown,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11724        if self.mode.is_single_line() {
11725            cx.propagate();
11726            return;
11727        }
11728
11729        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11730        let buffer = self.buffer.read(cx).snapshot(cx);
11731
11732        let mut edits = Vec::new();
11733        let mut unfold_ranges = Vec::new();
11734        let mut refold_creases = Vec::new();
11735
11736        let selections = self.selections.all::<Point>(cx);
11737        let mut selections = selections.iter().peekable();
11738        let mut contiguous_row_selections = Vec::new();
11739        let mut new_selections = Vec::new();
11740
11741        while let Some(selection) = selections.next() {
11742            // Find all the selections that span a contiguous row range
11743            let (start_row, end_row) = consume_contiguous_rows(
11744                &mut contiguous_row_selections,
11745                selection,
11746                &display_map,
11747                &mut selections,
11748            );
11749
11750            // Move the text spanned by the row range to be after the last line of the row range
11751            if end_row.0 <= buffer.max_point().row {
11752                let range_to_move =
11753                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11754                let insertion_point = display_map
11755                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11756                    .0;
11757
11758                // Don't move lines across excerpt boundaries
11759                if buffer
11760                    .excerpt_containing(range_to_move.start..insertion_point)
11761                    .is_some()
11762                {
11763                    let mut text = String::from("\n");
11764                    text.extend(buffer.text_for_range(range_to_move.clone()));
11765                    text.pop(); // Drop trailing newline
11766                    edits.push((
11767                        buffer.anchor_after(range_to_move.start)
11768                            ..buffer.anchor_before(range_to_move.end),
11769                        String::new(),
11770                    ));
11771                    let insertion_anchor = buffer.anchor_after(insertion_point);
11772                    edits.push((insertion_anchor..insertion_anchor, text));
11773
11774                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11775
11776                    // Move selections down
11777                    new_selections.extend(contiguous_row_selections.drain(..).map(
11778                        |mut selection| {
11779                            selection.start.row += row_delta;
11780                            selection.end.row += row_delta;
11781                            selection
11782                        },
11783                    ));
11784
11785                    // Move folds down
11786                    unfold_ranges.push(range_to_move.clone());
11787                    for fold in display_map.folds_in_range(
11788                        buffer.anchor_before(range_to_move.start)
11789                            ..buffer.anchor_after(range_to_move.end),
11790                    ) {
11791                        let mut start = fold.range.start.to_point(&buffer);
11792                        let mut end = fold.range.end.to_point(&buffer);
11793                        start.row += row_delta;
11794                        end.row += row_delta;
11795                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11796                    }
11797                }
11798            }
11799
11800            // If we didn't move line(s), preserve the existing selections
11801            new_selections.append(&mut contiguous_row_selections);
11802        }
11803
11804        self.transact(window, cx, |this, window, cx| {
11805            this.unfold_ranges(&unfold_ranges, true, true, cx);
11806            this.buffer.update(cx, |buffer, cx| {
11807                for (range, text) in edits {
11808                    buffer.edit([(range, text)], None, cx);
11809                }
11810            });
11811            this.fold_creases(refold_creases, true, window, cx);
11812            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11813        });
11814    }
11815
11816    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11817        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11818        let text_layout_details = &self.text_layout_details(window);
11819        self.transact(window, cx, |this, window, cx| {
11820            let edits = this.change_selections(Default::default(), window, cx, |s| {
11821                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11822                s.move_with(|display_map, selection| {
11823                    if !selection.is_empty() {
11824                        return;
11825                    }
11826
11827                    let mut head = selection.head();
11828                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11829                    if head.column() == display_map.line_len(head.row()) {
11830                        transpose_offset = display_map
11831                            .buffer_snapshot
11832                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11833                    }
11834
11835                    if transpose_offset == 0 {
11836                        return;
11837                    }
11838
11839                    *head.column_mut() += 1;
11840                    head = display_map.clip_point(head, Bias::Right);
11841                    let goal = SelectionGoal::HorizontalPosition(
11842                        display_map
11843                            .x_for_display_point(head, text_layout_details)
11844                            .into(),
11845                    );
11846                    selection.collapse_to(head, goal);
11847
11848                    let transpose_start = display_map
11849                        .buffer_snapshot
11850                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11851                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11852                        let transpose_end = display_map
11853                            .buffer_snapshot
11854                            .clip_offset(transpose_offset + 1, Bias::Right);
11855                        if let Some(ch) =
11856                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11857                        {
11858                            edits.push((transpose_start..transpose_offset, String::new()));
11859                            edits.push((transpose_end..transpose_end, ch.to_string()));
11860                        }
11861                    }
11862                });
11863                edits
11864            });
11865            this.buffer
11866                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11867            let selections = this.selections.all::<usize>(cx);
11868            this.change_selections(Default::default(), window, cx, |s| {
11869                s.select(selections);
11870            });
11871        });
11872    }
11873
11874    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11875        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11876        if self.mode.is_single_line() {
11877            cx.propagate();
11878            return;
11879        }
11880
11881        self.rewrap_impl(RewrapOptions::default(), cx)
11882    }
11883
11884    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11885        let buffer = self.buffer.read(cx).snapshot(cx);
11886        let selections = self.selections.all::<Point>(cx);
11887
11888        #[derive(Clone, Debug, PartialEq)]
11889        enum CommentFormat {
11890            /// single line comment, with prefix for line
11891            Line(String),
11892            /// single line within a block comment, with prefix for line
11893            BlockLine(String),
11894            /// a single line of a block comment that includes the initial delimiter
11895            BlockCommentWithStart(BlockCommentConfig),
11896            /// a single line of a block comment that includes the ending delimiter
11897            BlockCommentWithEnd(BlockCommentConfig),
11898        }
11899
11900        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11901        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11902            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11903                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11904                .peekable();
11905
11906            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11907                row
11908            } else {
11909                return Vec::new();
11910            };
11911
11912            let language_settings = buffer.language_settings_at(selection.head(), cx);
11913            let language_scope = buffer.language_scope_at(selection.head());
11914
11915            let indent_and_prefix_for_row =
11916                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
11917                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11918                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
11919                        &language_scope
11920                    {
11921                        let indent_end = Point::new(row, indent.len);
11922                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11923                        let line_text_after_indent = buffer
11924                            .text_for_range(indent_end..line_end)
11925                            .collect::<String>();
11926
11927                        let is_within_comment_override = buffer
11928                            .language_scope_at(indent_end)
11929                            .is_some_and(|scope| scope.override_name() == Some("comment"));
11930                        let comment_delimiters = if is_within_comment_override {
11931                            // we are within a comment syntax node, but we don't
11932                            // yet know what kind of comment: block, doc or line
11933                            match (
11934                                language_scope.documentation_comment(),
11935                                language_scope.block_comment(),
11936                            ) {
11937                                (Some(config), _) | (_, Some(config))
11938                                    if buffer.contains_str_at(indent_end, &config.start) =>
11939                                {
11940                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
11941                                }
11942                                (Some(config), _) | (_, Some(config))
11943                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
11944                                {
11945                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
11946                                }
11947                                (Some(config), _) | (_, Some(config))
11948                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
11949                                {
11950                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
11951                                }
11952                                (_, _) => language_scope
11953                                    .line_comment_prefixes()
11954                                    .iter()
11955                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11956                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
11957                            }
11958                        } else {
11959                            // we not in an overridden comment node, but we may
11960                            // be within a non-overridden line comment node
11961                            language_scope
11962                                .line_comment_prefixes()
11963                                .iter()
11964                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11965                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
11966                        };
11967
11968                        let rewrap_prefix = language_scope
11969                            .rewrap_prefixes()
11970                            .iter()
11971                            .find_map(|prefix_regex| {
11972                                prefix_regex.find(&line_text_after_indent).map(|mat| {
11973                                    if mat.start() == 0 {
11974                                        Some(mat.as_str().to_string())
11975                                    } else {
11976                                        None
11977                                    }
11978                                })
11979                            })
11980                            .flatten();
11981                        (comment_delimiters, rewrap_prefix)
11982                    } else {
11983                        (None, None)
11984                    };
11985                    (indent, comment_prefix, rewrap_prefix)
11986                };
11987
11988            let mut ranges = Vec::new();
11989            let from_empty_selection = selection.is_empty();
11990
11991            let mut current_range_start = first_row;
11992            let mut prev_row = first_row;
11993            let (
11994                mut current_range_indent,
11995                mut current_range_comment_delimiters,
11996                mut current_range_rewrap_prefix,
11997            ) = indent_and_prefix_for_row(first_row);
11998
11999            for row in non_blank_rows_iter.skip(1) {
12000                let has_paragraph_break = row > prev_row + 1;
12001
12002                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12003                    indent_and_prefix_for_row(row);
12004
12005                let has_indent_change = row_indent != current_range_indent;
12006                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12007
12008                let has_boundary_change = has_comment_change
12009                    || row_rewrap_prefix.is_some()
12010                    || (has_indent_change && current_range_comment_delimiters.is_some());
12011
12012                if has_paragraph_break || has_boundary_change {
12013                    ranges.push((
12014                        language_settings.clone(),
12015                        Point::new(current_range_start, 0)
12016                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12017                        current_range_indent,
12018                        current_range_comment_delimiters.clone(),
12019                        current_range_rewrap_prefix.clone(),
12020                        from_empty_selection,
12021                    ));
12022                    current_range_start = row;
12023                    current_range_indent = row_indent;
12024                    current_range_comment_delimiters = row_comment_delimiters;
12025                    current_range_rewrap_prefix = row_rewrap_prefix;
12026                }
12027                prev_row = row;
12028            }
12029
12030            ranges.push((
12031                language_settings.clone(),
12032                Point::new(current_range_start, 0)
12033                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12034                current_range_indent,
12035                current_range_comment_delimiters,
12036                current_range_rewrap_prefix,
12037                from_empty_selection,
12038            ));
12039
12040            ranges
12041        });
12042
12043        let mut edits = Vec::new();
12044        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12045
12046        for (
12047            language_settings,
12048            wrap_range,
12049            mut indent_size,
12050            comment_prefix,
12051            rewrap_prefix,
12052            from_empty_selection,
12053        ) in wrap_ranges
12054        {
12055            let mut start_row = wrap_range.start.row;
12056            let mut end_row = wrap_range.end.row;
12057
12058            // Skip selections that overlap with a range that has already been rewrapped.
12059            let selection_range = start_row..end_row;
12060            if rewrapped_row_ranges
12061                .iter()
12062                .any(|range| range.overlaps(&selection_range))
12063            {
12064                continue;
12065            }
12066
12067            let tab_size = language_settings.tab_size;
12068
12069            let (line_prefix, inside_comment) = match &comment_prefix {
12070                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12071                    (Some(prefix.as_str()), true)
12072                }
12073                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12074                    (Some(prefix.as_ref()), true)
12075                }
12076                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12077                    start: _,
12078                    end: _,
12079                    prefix,
12080                    tab_size,
12081                })) => {
12082                    indent_size.len += tab_size;
12083                    (Some(prefix.as_ref()), true)
12084                }
12085                None => (None, false),
12086            };
12087            let indent_prefix = indent_size.chars().collect::<String>();
12088            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12089
12090            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12091                RewrapBehavior::InComments => inside_comment,
12092                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12093                RewrapBehavior::Anywhere => true,
12094            };
12095
12096            let should_rewrap = options.override_language_settings
12097                || allow_rewrap_based_on_language
12098                || self.hard_wrap.is_some();
12099            if !should_rewrap {
12100                continue;
12101            }
12102
12103            if from_empty_selection {
12104                'expand_upwards: while start_row > 0 {
12105                    let prev_row = start_row - 1;
12106                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12107                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12108                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12109                    {
12110                        start_row = prev_row;
12111                    } else {
12112                        break 'expand_upwards;
12113                    }
12114                }
12115
12116                'expand_downwards: while end_row < buffer.max_point().row {
12117                    let next_row = end_row + 1;
12118                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12119                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12120                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12121                    {
12122                        end_row = next_row;
12123                    } else {
12124                        break 'expand_downwards;
12125                    }
12126                }
12127            }
12128
12129            let start = Point::new(start_row, 0);
12130            let start_offset = start.to_offset(&buffer);
12131            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12132            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12133            let mut first_line_delimiter = None;
12134            let mut last_line_delimiter = None;
12135            let Some(lines_without_prefixes) = selection_text
12136                .lines()
12137                .enumerate()
12138                .map(|(ix, line)| {
12139                    let line_trimmed = line.trim_start();
12140                    if rewrap_prefix.is_some() && ix > 0 {
12141                        Ok(line_trimmed)
12142                    } else if let Some(
12143                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12144                            start,
12145                            prefix,
12146                            end,
12147                            tab_size,
12148                        })
12149                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12150                            start,
12151                            prefix,
12152                            end,
12153                            tab_size,
12154                        }),
12155                    ) = &comment_prefix
12156                    {
12157                        let line_trimmed = line_trimmed
12158                            .strip_prefix(start.as_ref())
12159                            .map(|s| {
12160                                let mut indent_size = indent_size;
12161                                indent_size.len -= tab_size;
12162                                let indent_prefix: String = indent_size.chars().collect();
12163                                first_line_delimiter = Some((indent_prefix, start));
12164                                s.trim_start()
12165                            })
12166                            .unwrap_or(line_trimmed);
12167                        let line_trimmed = line_trimmed
12168                            .strip_suffix(end.as_ref())
12169                            .map(|s| {
12170                                last_line_delimiter = Some(end);
12171                                s.trim_end()
12172                            })
12173                            .unwrap_or(line_trimmed);
12174                        let line_trimmed = line_trimmed
12175                            .strip_prefix(prefix.as_ref())
12176                            .unwrap_or(line_trimmed);
12177                        Ok(line_trimmed)
12178                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12179                        line_trimmed.strip_prefix(prefix).with_context(|| {
12180                            format!("line did not start with prefix {prefix:?}: {line:?}")
12181                        })
12182                    } else {
12183                        line_trimmed
12184                            .strip_prefix(&line_prefix.trim_start())
12185                            .with_context(|| {
12186                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12187                            })
12188                    }
12189                })
12190                .collect::<Result<Vec<_>, _>>()
12191                .log_err()
12192            else {
12193                continue;
12194            };
12195
12196            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12197                buffer
12198                    .language_settings_at(Point::new(start_row, 0), cx)
12199                    .preferred_line_length as usize
12200            });
12201
12202            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12203                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12204            } else {
12205                line_prefix.clone()
12206            };
12207
12208            let wrapped_text = {
12209                let mut wrapped_text = wrap_with_prefix(
12210                    line_prefix,
12211                    subsequent_lines_prefix,
12212                    lines_without_prefixes.join("\n"),
12213                    wrap_column,
12214                    tab_size,
12215                    options.preserve_existing_whitespace,
12216                );
12217
12218                if let Some((indent, delimiter)) = first_line_delimiter {
12219                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12220                }
12221                if let Some(last_line) = last_line_delimiter {
12222                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12223                }
12224
12225                wrapped_text
12226            };
12227
12228            // TODO: should always use char-based diff while still supporting cursor behavior that
12229            // matches vim.
12230            let mut diff_options = DiffOptions::default();
12231            if options.override_language_settings {
12232                diff_options.max_word_diff_len = 0;
12233                diff_options.max_word_diff_line_count = 0;
12234            } else {
12235                diff_options.max_word_diff_len = usize::MAX;
12236                diff_options.max_word_diff_line_count = usize::MAX;
12237            }
12238
12239            for (old_range, new_text) in
12240                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12241            {
12242                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12243                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12244                edits.push((edit_start..edit_end, new_text));
12245            }
12246
12247            rewrapped_row_ranges.push(start_row..=end_row);
12248        }
12249
12250        self.buffer
12251            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12252    }
12253
12254    pub fn cut_common(
12255        &mut self,
12256        cut_no_selection_line: bool,
12257        window: &mut Window,
12258        cx: &mut Context<Self>,
12259    ) -> ClipboardItem {
12260        let mut text = String::new();
12261        let buffer = self.buffer.read(cx).snapshot(cx);
12262        let mut selections = self.selections.all::<Point>(cx);
12263        let mut clipboard_selections = Vec::with_capacity(selections.len());
12264        {
12265            let max_point = buffer.max_point();
12266            let mut is_first = true;
12267            for selection in &mut selections {
12268                let is_entire_line =
12269                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode;
12270                if is_entire_line {
12271                    selection.start = Point::new(selection.start.row, 0);
12272                    if !selection.is_empty() && selection.end.column == 0 {
12273                        selection.end = cmp::min(max_point, selection.end);
12274                    } else {
12275                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12276                    }
12277                    selection.goal = SelectionGoal::None;
12278                }
12279                if is_first {
12280                    is_first = false;
12281                } else {
12282                    text += "\n";
12283                }
12284                let mut len = 0;
12285                for chunk in buffer.text_for_range(selection.start..selection.end) {
12286                    text.push_str(chunk);
12287                    len += chunk.len();
12288                }
12289                clipboard_selections.push(ClipboardSelection {
12290                    len,
12291                    is_entire_line,
12292                    first_line_indent: buffer
12293                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12294                        .len,
12295                });
12296            }
12297        }
12298
12299        self.transact(window, cx, |this, window, cx| {
12300            this.change_selections(Default::default(), window, cx, |s| {
12301                s.select(selections);
12302            });
12303            this.insert("", window, cx);
12304        });
12305        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12306    }
12307
12308    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310        let item = self.cut_common(true, window, cx);
12311        cx.write_to_clipboard(item);
12312    }
12313
12314    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12316        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12317            s.move_with(|snapshot, sel| {
12318                if sel.is_empty() {
12319                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12320                }
12321                if sel.is_empty() {
12322                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12323                }
12324            });
12325        });
12326        let item = self.cut_common(true, window, cx);
12327        cx.set_global(KillRing(item))
12328    }
12329
12330    pub fn kill_ring_yank(
12331        &mut self,
12332        _: &KillRingYank,
12333        window: &mut Window,
12334        cx: &mut Context<Self>,
12335    ) {
12336        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12337        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12338            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12339                (kill_ring.text().to_string(), kill_ring.metadata_json())
12340            } else {
12341                return;
12342            }
12343        } else {
12344            return;
12345        };
12346        self.do_paste(&text, metadata, false, window, cx);
12347    }
12348
12349    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12350        self.do_copy(true, cx);
12351    }
12352
12353    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12354        self.do_copy(false, cx);
12355    }
12356
12357    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12358        let selections = self.selections.all::<Point>(cx);
12359        let buffer = self.buffer.read(cx).read(cx);
12360        let mut text = String::new();
12361
12362        let mut clipboard_selections = Vec::with_capacity(selections.len());
12363        {
12364            let max_point = buffer.max_point();
12365            let mut is_first = true;
12366            for selection in &selections {
12367                let mut start = selection.start;
12368                let mut end = selection.end;
12369                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12370                if is_entire_line {
12371                    start = Point::new(start.row, 0);
12372                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12373                }
12374
12375                let mut trimmed_selections = Vec::new();
12376                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12377                    let row = MultiBufferRow(start.row);
12378                    let first_indent = buffer.indent_size_for_line(row);
12379                    if first_indent.len == 0 || start.column > first_indent.len {
12380                        trimmed_selections.push(start..end);
12381                    } else {
12382                        trimmed_selections.push(
12383                            Point::new(row.0, first_indent.len)
12384                                ..Point::new(row.0, buffer.line_len(row)),
12385                        );
12386                        for row in start.row + 1..=end.row {
12387                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12388                            if row == end.row {
12389                                line_len = end.column;
12390                            }
12391                            if line_len == 0 {
12392                                trimmed_selections
12393                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12394                                continue;
12395                            }
12396                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12397                            if row_indent_size.len >= first_indent.len {
12398                                trimmed_selections.push(
12399                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12400                                );
12401                            } else {
12402                                trimmed_selections.clear();
12403                                trimmed_selections.push(start..end);
12404                                break;
12405                            }
12406                        }
12407                    }
12408                } else {
12409                    trimmed_selections.push(start..end);
12410                }
12411
12412                for trimmed_range in trimmed_selections {
12413                    if is_first {
12414                        is_first = false;
12415                    } else {
12416                        text += "\n";
12417                    }
12418                    let mut len = 0;
12419                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12420                        text.push_str(chunk);
12421                        len += chunk.len();
12422                    }
12423                    clipboard_selections.push(ClipboardSelection {
12424                        len,
12425                        is_entire_line,
12426                        first_line_indent: buffer
12427                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12428                            .len,
12429                    });
12430                }
12431            }
12432        }
12433
12434        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12435            text,
12436            clipboard_selections,
12437        ));
12438    }
12439
12440    pub fn do_paste(
12441        &mut self,
12442        text: &String,
12443        clipboard_selections: Option<Vec<ClipboardSelection>>,
12444        handle_entire_lines: bool,
12445        window: &mut Window,
12446        cx: &mut Context<Self>,
12447    ) {
12448        if self.read_only(cx) {
12449            return;
12450        }
12451
12452        let clipboard_text = Cow::Borrowed(text);
12453
12454        self.transact(window, cx, |this, window, cx| {
12455            let had_active_edit_prediction = this.has_active_edit_prediction();
12456
12457            if let Some(mut clipboard_selections) = clipboard_selections {
12458                let old_selections = this.selections.all::<usize>(cx);
12459                let all_selections_were_entire_line =
12460                    clipboard_selections.iter().all(|s| s.is_entire_line);
12461                let first_selection_indent_column =
12462                    clipboard_selections.first().map(|s| s.first_line_indent);
12463                if clipboard_selections.len() != old_selections.len() {
12464                    clipboard_selections.drain(..);
12465                }
12466                let cursor_offset = this.selections.last::<usize>(cx).head();
12467                let mut auto_indent_on_paste = true;
12468
12469                this.buffer.update(cx, |buffer, cx| {
12470                    let snapshot = buffer.read(cx);
12471                    auto_indent_on_paste = snapshot
12472                        .language_settings_at(cursor_offset, cx)
12473                        .auto_indent_on_paste;
12474
12475                    let mut start_offset = 0;
12476                    let mut edits = Vec::new();
12477                    let mut original_indent_columns = Vec::new();
12478                    for (ix, selection) in old_selections.iter().enumerate() {
12479                        let to_insert;
12480                        let entire_line;
12481                        let original_indent_column;
12482                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12483                            let end_offset = start_offset + clipboard_selection.len;
12484                            to_insert = &clipboard_text[start_offset..end_offset];
12485                            entire_line = clipboard_selection.is_entire_line;
12486                            start_offset = end_offset + 1;
12487                            original_indent_column = Some(clipboard_selection.first_line_indent);
12488                        } else {
12489                            to_insert = clipboard_text.as_str();
12490                            entire_line = all_selections_were_entire_line;
12491                            original_indent_column = first_selection_indent_column
12492                        }
12493
12494                        // If the corresponding selection was empty when this slice of the
12495                        // clipboard text was written, then the entire line containing the
12496                        // selection was copied. If this selection is also currently empty,
12497                        // then paste the line before the current line of the buffer.
12498                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12499                            let column = selection.start.to_point(&snapshot).column as usize;
12500                            let line_start = selection.start - column;
12501                            line_start..line_start
12502                        } else {
12503                            selection.range()
12504                        };
12505
12506                        edits.push((range, to_insert));
12507                        original_indent_columns.push(original_indent_column);
12508                    }
12509                    drop(snapshot);
12510
12511                    buffer.edit(
12512                        edits,
12513                        if auto_indent_on_paste {
12514                            Some(AutoindentMode::Block {
12515                                original_indent_columns,
12516                            })
12517                        } else {
12518                            None
12519                        },
12520                        cx,
12521                    );
12522                });
12523
12524                let selections = this.selections.all::<usize>(cx);
12525                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12526            } else {
12527                this.insert(&clipboard_text, window, cx);
12528            }
12529
12530            let trigger_in_words =
12531                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12532
12533            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12534        });
12535    }
12536
12537    pub fn diff_clipboard_with_selection(
12538        &mut self,
12539        _: &DiffClipboardWithSelection,
12540        window: &mut Window,
12541        cx: &mut Context<Self>,
12542    ) {
12543        let selections = self.selections.all::<usize>(cx);
12544
12545        if selections.is_empty() {
12546            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12547            return;
12548        };
12549
12550        let clipboard_text = match cx.read_from_clipboard() {
12551            Some(item) => match item.entries().first() {
12552                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12553                _ => None,
12554            },
12555            None => None,
12556        };
12557
12558        let Some(clipboard_text) = clipboard_text else {
12559            log::warn!("Clipboard doesn't contain text.");
12560            return;
12561        };
12562
12563        window.dispatch_action(
12564            Box::new(DiffClipboardWithSelectionData {
12565                clipboard_text,
12566                editor: cx.entity(),
12567            }),
12568            cx,
12569        );
12570    }
12571
12572    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12574        if let Some(item) = cx.read_from_clipboard() {
12575            let entries = item.entries();
12576
12577            match entries.first() {
12578                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12579                // of all the pasted entries.
12580                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12581                    .do_paste(
12582                        clipboard_string.text(),
12583                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12584                        true,
12585                        window,
12586                        cx,
12587                    ),
12588                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12589            }
12590        }
12591    }
12592
12593    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12594        if self.read_only(cx) {
12595            return;
12596        }
12597
12598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12599
12600        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12601            if let Some((selections, _)) =
12602                self.selection_history.transaction(transaction_id).cloned()
12603            {
12604                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12605                    s.select_anchors(selections.to_vec());
12606                });
12607            } else {
12608                log::error!(
12609                    "No entry in selection_history found for undo. \
12610                     This may correspond to a bug where undo does not update the selection. \
12611                     If this is occurring, please add details to \
12612                     https://github.com/zed-industries/zed/issues/22692"
12613                );
12614            }
12615            self.request_autoscroll(Autoscroll::fit(), cx);
12616            self.unmark_text(window, cx);
12617            self.refresh_edit_prediction(true, false, window, cx);
12618            cx.emit(EditorEvent::Edited { transaction_id });
12619            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12620        }
12621    }
12622
12623    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12624        if self.read_only(cx) {
12625            return;
12626        }
12627
12628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12629
12630        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12631            if let Some((_, Some(selections))) =
12632                self.selection_history.transaction(transaction_id).cloned()
12633            {
12634                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12635                    s.select_anchors(selections.to_vec());
12636                });
12637            } else {
12638                log::error!(
12639                    "No entry in selection_history found for redo. \
12640                     This may correspond to a bug where undo does not update the selection. \
12641                     If this is occurring, please add details to \
12642                     https://github.com/zed-industries/zed/issues/22692"
12643                );
12644            }
12645            self.request_autoscroll(Autoscroll::fit(), cx);
12646            self.unmark_text(window, cx);
12647            self.refresh_edit_prediction(true, false, window, cx);
12648            cx.emit(EditorEvent::Edited { transaction_id });
12649        }
12650    }
12651
12652    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12653        self.buffer
12654            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12655    }
12656
12657    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12658        self.buffer
12659            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12660    }
12661
12662    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12664        self.change_selections(Default::default(), window, cx, |s| {
12665            s.move_with(|map, selection| {
12666                let cursor = if selection.is_empty() {
12667                    movement::left(map, selection.start)
12668                } else {
12669                    selection.start
12670                };
12671                selection.collapse_to(cursor, SelectionGoal::None);
12672            });
12673        })
12674    }
12675
12676    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12678        self.change_selections(Default::default(), window, cx, |s| {
12679            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12680        })
12681    }
12682
12683    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12685        self.change_selections(Default::default(), window, cx, |s| {
12686            s.move_with(|map, selection| {
12687                let cursor = if selection.is_empty() {
12688                    movement::right(map, selection.end)
12689                } else {
12690                    selection.end
12691                };
12692                selection.collapse_to(cursor, SelectionGoal::None)
12693            });
12694        })
12695    }
12696
12697    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12699        self.change_selections(Default::default(), window, cx, |s| {
12700            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12701        })
12702    }
12703
12704    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12705        if self.take_rename(true, window, cx).is_some() {
12706            return;
12707        }
12708
12709        if self.mode.is_single_line() {
12710            cx.propagate();
12711            return;
12712        }
12713
12714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12715
12716        let text_layout_details = &self.text_layout_details(window);
12717        let selection_count = self.selections.count();
12718        let first_selection = self.selections.first_anchor();
12719
12720        self.change_selections(Default::default(), window, cx, |s| {
12721            s.move_with(|map, selection| {
12722                if !selection.is_empty() {
12723                    selection.goal = SelectionGoal::None;
12724                }
12725                let (cursor, goal) = movement::up(
12726                    map,
12727                    selection.start,
12728                    selection.goal,
12729                    false,
12730                    text_layout_details,
12731                );
12732                selection.collapse_to(cursor, goal);
12733            });
12734        });
12735
12736        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12737        {
12738            cx.propagate();
12739        }
12740    }
12741
12742    pub fn move_up_by_lines(
12743        &mut self,
12744        action: &MoveUpByLines,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        if self.take_rename(true, window, cx).is_some() {
12749            return;
12750        }
12751
12752        if self.mode.is_single_line() {
12753            cx.propagate();
12754            return;
12755        }
12756
12757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12758
12759        let text_layout_details = &self.text_layout_details(window);
12760
12761        self.change_selections(Default::default(), window, cx, |s| {
12762            s.move_with(|map, selection| {
12763                if !selection.is_empty() {
12764                    selection.goal = SelectionGoal::None;
12765                }
12766                let (cursor, goal) = movement::up_by_rows(
12767                    map,
12768                    selection.start,
12769                    action.lines,
12770                    selection.goal,
12771                    false,
12772                    text_layout_details,
12773                );
12774                selection.collapse_to(cursor, goal);
12775            });
12776        })
12777    }
12778
12779    pub fn move_down_by_lines(
12780        &mut self,
12781        action: &MoveDownByLines,
12782        window: &mut Window,
12783        cx: &mut Context<Self>,
12784    ) {
12785        if self.take_rename(true, window, cx).is_some() {
12786            return;
12787        }
12788
12789        if self.mode.is_single_line() {
12790            cx.propagate();
12791            return;
12792        }
12793
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12795
12796        let text_layout_details = &self.text_layout_details(window);
12797
12798        self.change_selections(Default::default(), window, cx, |s| {
12799            s.move_with(|map, selection| {
12800                if !selection.is_empty() {
12801                    selection.goal = SelectionGoal::None;
12802                }
12803                let (cursor, goal) = movement::down_by_rows(
12804                    map,
12805                    selection.start,
12806                    action.lines,
12807                    selection.goal,
12808                    false,
12809                    text_layout_details,
12810                );
12811                selection.collapse_to(cursor, goal);
12812            });
12813        })
12814    }
12815
12816    pub fn select_down_by_lines(
12817        &mut self,
12818        action: &SelectDownByLines,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12823        let text_layout_details = &self.text_layout_details(window);
12824        self.change_selections(Default::default(), window, cx, |s| {
12825            s.move_heads_with(|map, head, goal| {
12826                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12827            })
12828        })
12829    }
12830
12831    pub fn select_up_by_lines(
12832        &mut self,
12833        action: &SelectUpByLines,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12838        let text_layout_details = &self.text_layout_details(window);
12839        self.change_selections(Default::default(), window, cx, |s| {
12840            s.move_heads_with(|map, head, goal| {
12841                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12842            })
12843        })
12844    }
12845
12846    pub fn select_page_up(
12847        &mut self,
12848        _: &SelectPageUp,
12849        window: &mut Window,
12850        cx: &mut Context<Self>,
12851    ) {
12852        let Some(row_count) = self.visible_row_count() else {
12853            return;
12854        };
12855
12856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12857
12858        let text_layout_details = &self.text_layout_details(window);
12859
12860        self.change_selections(Default::default(), window, cx, |s| {
12861            s.move_heads_with(|map, head, goal| {
12862                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12863            })
12864        })
12865    }
12866
12867    pub fn move_page_up(
12868        &mut self,
12869        action: &MovePageUp,
12870        window: &mut Window,
12871        cx: &mut Context<Self>,
12872    ) {
12873        if self.take_rename(true, window, cx).is_some() {
12874            return;
12875        }
12876
12877        if self
12878            .context_menu
12879            .borrow_mut()
12880            .as_mut()
12881            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12882            .unwrap_or(false)
12883        {
12884            return;
12885        }
12886
12887        if matches!(self.mode, EditorMode::SingleLine) {
12888            cx.propagate();
12889            return;
12890        }
12891
12892        let Some(row_count) = self.visible_row_count() else {
12893            return;
12894        };
12895
12896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12897
12898        let effects = if action.center_cursor {
12899            SelectionEffects::scroll(Autoscroll::center())
12900        } else {
12901            SelectionEffects::default()
12902        };
12903
12904        let text_layout_details = &self.text_layout_details(window);
12905
12906        self.change_selections(effects, window, cx, |s| {
12907            s.move_with(|map, selection| {
12908                if !selection.is_empty() {
12909                    selection.goal = SelectionGoal::None;
12910                }
12911                let (cursor, goal) = movement::up_by_rows(
12912                    map,
12913                    selection.end,
12914                    row_count,
12915                    selection.goal,
12916                    false,
12917                    text_layout_details,
12918                );
12919                selection.collapse_to(cursor, goal);
12920            });
12921        });
12922    }
12923
12924    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12925        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12926        let text_layout_details = &self.text_layout_details(window);
12927        self.change_selections(Default::default(), window, cx, |s| {
12928            s.move_heads_with(|map, head, goal| {
12929                movement::up(map, head, goal, false, text_layout_details)
12930            })
12931        })
12932    }
12933
12934    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12935        self.take_rename(true, window, cx);
12936
12937        if self.mode.is_single_line() {
12938            cx.propagate();
12939            return;
12940        }
12941
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12943
12944        let text_layout_details = &self.text_layout_details(window);
12945        let selection_count = self.selections.count();
12946        let first_selection = self.selections.first_anchor();
12947
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_with(|map, selection| {
12950                if !selection.is_empty() {
12951                    selection.goal = SelectionGoal::None;
12952                }
12953                let (cursor, goal) = movement::down(
12954                    map,
12955                    selection.end,
12956                    selection.goal,
12957                    false,
12958                    text_layout_details,
12959                );
12960                selection.collapse_to(cursor, goal);
12961            });
12962        });
12963
12964        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12965        {
12966            cx.propagate();
12967        }
12968    }
12969
12970    pub fn select_page_down(
12971        &mut self,
12972        _: &SelectPageDown,
12973        window: &mut Window,
12974        cx: &mut Context<Self>,
12975    ) {
12976        let Some(row_count) = self.visible_row_count() else {
12977            return;
12978        };
12979
12980        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12981
12982        let text_layout_details = &self.text_layout_details(window);
12983
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_heads_with(|map, head, goal| {
12986                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12987            })
12988        })
12989    }
12990
12991    pub fn move_page_down(
12992        &mut self,
12993        action: &MovePageDown,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) {
12997        if self.take_rename(true, window, cx).is_some() {
12998            return;
12999        }
13000
13001        if self
13002            .context_menu
13003            .borrow_mut()
13004            .as_mut()
13005            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13006            .unwrap_or(false)
13007        {
13008            return;
13009        }
13010
13011        if matches!(self.mode, EditorMode::SingleLine) {
13012            cx.propagate();
13013            return;
13014        }
13015
13016        let Some(row_count) = self.visible_row_count() else {
13017            return;
13018        };
13019
13020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13021
13022        let effects = if action.center_cursor {
13023            SelectionEffects::scroll(Autoscroll::center())
13024        } else {
13025            SelectionEffects::default()
13026        };
13027
13028        let text_layout_details = &self.text_layout_details(window);
13029        self.change_selections(effects, window, cx, |s| {
13030            s.move_with(|map, selection| {
13031                if !selection.is_empty() {
13032                    selection.goal = SelectionGoal::None;
13033                }
13034                let (cursor, goal) = movement::down_by_rows(
13035                    map,
13036                    selection.end,
13037                    row_count,
13038                    selection.goal,
13039                    false,
13040                    text_layout_details,
13041                );
13042                selection.collapse_to(cursor, goal);
13043            });
13044        });
13045    }
13046
13047    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13049        let text_layout_details = &self.text_layout_details(window);
13050        self.change_selections(Default::default(), window, cx, |s| {
13051            s.move_heads_with(|map, head, goal| {
13052                movement::down(map, head, goal, false, text_layout_details)
13053            })
13054        });
13055    }
13056
13057    pub fn context_menu_first(
13058        &mut self,
13059        _: &ContextMenuFirst,
13060        window: &mut Window,
13061        cx: &mut Context<Self>,
13062    ) {
13063        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13064            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13065        }
13066    }
13067
13068    pub fn context_menu_prev(
13069        &mut self,
13070        _: &ContextMenuPrevious,
13071        window: &mut Window,
13072        cx: &mut Context<Self>,
13073    ) {
13074        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13075            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13076        }
13077    }
13078
13079    pub fn context_menu_next(
13080        &mut self,
13081        _: &ContextMenuNext,
13082        window: &mut Window,
13083        cx: &mut Context<Self>,
13084    ) {
13085        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13086            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13087        }
13088    }
13089
13090    pub fn context_menu_last(
13091        &mut self,
13092        _: &ContextMenuLast,
13093        window: &mut Window,
13094        cx: &mut Context<Self>,
13095    ) {
13096        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13097            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13098        }
13099    }
13100
13101    pub fn signature_help_prev(
13102        &mut self,
13103        _: &SignatureHelpPrevious,
13104        _: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        if let Some(popover) = self.signature_help_state.popover_mut() {
13108            if popover.current_signature == 0 {
13109                popover.current_signature = popover.signatures.len() - 1;
13110            } else {
13111                popover.current_signature -= 1;
13112            }
13113            cx.notify();
13114        }
13115    }
13116
13117    pub fn signature_help_next(
13118        &mut self,
13119        _: &SignatureHelpNext,
13120        _: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        if let Some(popover) = self.signature_help_state.popover_mut() {
13124            if popover.current_signature + 1 == popover.signatures.len() {
13125                popover.current_signature = 0;
13126            } else {
13127                popover.current_signature += 1;
13128            }
13129            cx.notify();
13130        }
13131    }
13132
13133    pub fn move_to_previous_word_start(
13134        &mut self,
13135        _: &MoveToPreviousWordStart,
13136        window: &mut Window,
13137        cx: &mut Context<Self>,
13138    ) {
13139        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13140        self.change_selections(Default::default(), window, cx, |s| {
13141            s.move_cursors_with(|map, head, _| {
13142                (
13143                    movement::previous_word_start(map, head),
13144                    SelectionGoal::None,
13145                )
13146            });
13147        })
13148    }
13149
13150    pub fn move_to_previous_subword_start(
13151        &mut self,
13152        _: &MoveToPreviousSubwordStart,
13153        window: &mut Window,
13154        cx: &mut Context<Self>,
13155    ) {
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13157        self.change_selections(Default::default(), window, cx, |s| {
13158            s.move_cursors_with(|map, head, _| {
13159                (
13160                    movement::previous_subword_start(map, head),
13161                    SelectionGoal::None,
13162                )
13163            });
13164        })
13165    }
13166
13167    pub fn select_to_previous_word_start(
13168        &mut self,
13169        _: &SelectToPreviousWordStart,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13174        self.change_selections(Default::default(), window, cx, |s| {
13175            s.move_heads_with(|map, head, _| {
13176                (
13177                    movement::previous_word_start(map, head),
13178                    SelectionGoal::None,
13179                )
13180            });
13181        })
13182    }
13183
13184    pub fn select_to_previous_subword_start(
13185        &mut self,
13186        _: &SelectToPreviousSubwordStart,
13187        window: &mut Window,
13188        cx: &mut Context<Self>,
13189    ) {
13190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13191        self.change_selections(Default::default(), window, cx, |s| {
13192            s.move_heads_with(|map, head, _| {
13193                (
13194                    movement::previous_subword_start(map, head),
13195                    SelectionGoal::None,
13196                )
13197            });
13198        })
13199    }
13200
13201    pub fn delete_to_previous_word_start(
13202        &mut self,
13203        action: &DeleteToPreviousWordStart,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13208        self.transact(window, cx, |this, window, cx| {
13209            this.select_autoclose_pair(window, cx);
13210            this.change_selections(Default::default(), window, cx, |s| {
13211                s.move_with(|map, selection| {
13212                    if selection.is_empty() {
13213                        let mut cursor = if action.ignore_newlines {
13214                            movement::previous_word_start(map, selection.head())
13215                        } else {
13216                            movement::previous_word_start_or_newline(map, selection.head())
13217                        };
13218                        cursor = movement::adjust_greedy_deletion(
13219                            map,
13220                            selection.head(),
13221                            cursor,
13222                            action.ignore_brackets,
13223                        );
13224                        selection.set_head(cursor, SelectionGoal::None);
13225                    }
13226                });
13227            });
13228            this.insert("", window, cx);
13229        });
13230    }
13231
13232    pub fn delete_to_previous_subword_start(
13233        &mut self,
13234        _: &DeleteToPreviousSubwordStart,
13235        window: &mut Window,
13236        cx: &mut Context<Self>,
13237    ) {
13238        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13239        self.transact(window, cx, |this, window, cx| {
13240            this.select_autoclose_pair(window, cx);
13241            this.change_selections(Default::default(), window, cx, |s| {
13242                s.move_with(|map, selection| {
13243                    if selection.is_empty() {
13244                        let mut cursor = movement::previous_subword_start(map, selection.head());
13245                        cursor =
13246                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13247                        selection.set_head(cursor, SelectionGoal::None);
13248                    }
13249                });
13250            });
13251            this.insert("", window, cx);
13252        });
13253    }
13254
13255    pub fn move_to_next_word_end(
13256        &mut self,
13257        _: &MoveToNextWordEnd,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13262        self.change_selections(Default::default(), window, cx, |s| {
13263            s.move_cursors_with(|map, head, _| {
13264                (movement::next_word_end(map, head), SelectionGoal::None)
13265            });
13266        })
13267    }
13268
13269    pub fn move_to_next_subword_end(
13270        &mut self,
13271        _: &MoveToNextSubwordEnd,
13272        window: &mut Window,
13273        cx: &mut Context<Self>,
13274    ) {
13275        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13276        self.change_selections(Default::default(), window, cx, |s| {
13277            s.move_cursors_with(|map, head, _| {
13278                (movement::next_subword_end(map, head), SelectionGoal::None)
13279            });
13280        })
13281    }
13282
13283    pub fn select_to_next_word_end(
13284        &mut self,
13285        _: &SelectToNextWordEnd,
13286        window: &mut Window,
13287        cx: &mut Context<Self>,
13288    ) {
13289        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13290        self.change_selections(Default::default(), window, cx, |s| {
13291            s.move_heads_with(|map, head, _| {
13292                (movement::next_word_end(map, head), SelectionGoal::None)
13293            });
13294        })
13295    }
13296
13297    pub fn select_to_next_subword_end(
13298        &mut self,
13299        _: &SelectToNextSubwordEnd,
13300        window: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13304        self.change_selections(Default::default(), window, cx, |s| {
13305            s.move_heads_with(|map, head, _| {
13306                (movement::next_subword_end(map, head), SelectionGoal::None)
13307            });
13308        })
13309    }
13310
13311    pub fn delete_to_next_word_end(
13312        &mut self,
13313        action: &DeleteToNextWordEnd,
13314        window: &mut Window,
13315        cx: &mut Context<Self>,
13316    ) {
13317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13318        self.transact(window, cx, |this, window, cx| {
13319            this.change_selections(Default::default(), window, cx, |s| {
13320                s.move_with(|map, selection| {
13321                    if selection.is_empty() {
13322                        let mut cursor = if action.ignore_newlines {
13323                            movement::next_word_end(map, selection.head())
13324                        } else {
13325                            movement::next_word_end_or_newline(map, selection.head())
13326                        };
13327                        cursor = movement::adjust_greedy_deletion(
13328                            map,
13329                            selection.head(),
13330                            cursor,
13331                            action.ignore_brackets,
13332                        );
13333                        selection.set_head(cursor, SelectionGoal::None);
13334                    }
13335                });
13336            });
13337            this.insert("", window, cx);
13338        });
13339    }
13340
13341    pub fn delete_to_next_subword_end(
13342        &mut self,
13343        _: &DeleteToNextSubwordEnd,
13344        window: &mut Window,
13345        cx: &mut Context<Self>,
13346    ) {
13347        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13348        self.transact(window, cx, |this, window, cx| {
13349            this.change_selections(Default::default(), window, cx, |s| {
13350                s.move_with(|map, selection| {
13351                    if selection.is_empty() {
13352                        let mut cursor = movement::next_subword_end(map, selection.head());
13353                        cursor =
13354                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13355                        selection.set_head(cursor, SelectionGoal::None);
13356                    }
13357                });
13358            });
13359            this.insert("", window, cx);
13360        });
13361    }
13362
13363    pub fn move_to_beginning_of_line(
13364        &mut self,
13365        action: &MoveToBeginningOfLine,
13366        window: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) {
13369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13370        self.change_selections(Default::default(), window, cx, |s| {
13371            s.move_cursors_with(|map, head, _| {
13372                (
13373                    movement::indented_line_beginning(
13374                        map,
13375                        head,
13376                        action.stop_at_soft_wraps,
13377                        action.stop_at_indent,
13378                    ),
13379                    SelectionGoal::None,
13380                )
13381            });
13382        })
13383    }
13384
13385    pub fn select_to_beginning_of_line(
13386        &mut self,
13387        action: &SelectToBeginningOfLine,
13388        window: &mut Window,
13389        cx: &mut Context<Self>,
13390    ) {
13391        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13392        self.change_selections(Default::default(), window, cx, |s| {
13393            s.move_heads_with(|map, head, _| {
13394                (
13395                    movement::indented_line_beginning(
13396                        map,
13397                        head,
13398                        action.stop_at_soft_wraps,
13399                        action.stop_at_indent,
13400                    ),
13401                    SelectionGoal::None,
13402                )
13403            });
13404        });
13405    }
13406
13407    pub fn delete_to_beginning_of_line(
13408        &mut self,
13409        action: &DeleteToBeginningOfLine,
13410        window: &mut Window,
13411        cx: &mut Context<Self>,
13412    ) {
13413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13414        self.transact(window, cx, |this, window, cx| {
13415            this.change_selections(Default::default(), window, cx, |s| {
13416                s.move_with(|_, selection| {
13417                    selection.reversed = true;
13418                });
13419            });
13420
13421            this.select_to_beginning_of_line(
13422                &SelectToBeginningOfLine {
13423                    stop_at_soft_wraps: false,
13424                    stop_at_indent: action.stop_at_indent,
13425                },
13426                window,
13427                cx,
13428            );
13429            this.backspace(&Backspace, window, cx);
13430        });
13431    }
13432
13433    pub fn move_to_end_of_line(
13434        &mut self,
13435        action: &MoveToEndOfLine,
13436        window: &mut Window,
13437        cx: &mut Context<Self>,
13438    ) {
13439        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13440        self.change_selections(Default::default(), window, cx, |s| {
13441            s.move_cursors_with(|map, head, _| {
13442                (
13443                    movement::line_end(map, head, action.stop_at_soft_wraps),
13444                    SelectionGoal::None,
13445                )
13446            });
13447        })
13448    }
13449
13450    pub fn select_to_end_of_line(
13451        &mut self,
13452        action: &SelectToEndOfLine,
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_heads_with(|map, head, _| {
13459                (
13460                    movement::line_end(map, head, action.stop_at_soft_wraps),
13461                    SelectionGoal::None,
13462                )
13463            });
13464        })
13465    }
13466
13467    pub fn delete_to_end_of_line(
13468        &mut self,
13469        _: &DeleteToEndOfLine,
13470        window: &mut Window,
13471        cx: &mut Context<Self>,
13472    ) {
13473        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13474        self.transact(window, cx, |this, window, cx| {
13475            this.select_to_end_of_line(
13476                &SelectToEndOfLine {
13477                    stop_at_soft_wraps: false,
13478                },
13479                window,
13480                cx,
13481            );
13482            this.delete(&Delete, window, cx);
13483        });
13484    }
13485
13486    pub fn cut_to_end_of_line(
13487        &mut self,
13488        action: &CutToEndOfLine,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13493        self.transact(window, cx, |this, window, cx| {
13494            this.select_to_end_of_line(
13495                &SelectToEndOfLine {
13496                    stop_at_soft_wraps: false,
13497                },
13498                window,
13499                cx,
13500            );
13501            if !action.stop_at_newlines {
13502                this.change_selections(Default::default(), window, cx, |s| {
13503                    s.move_with(|_, sel| {
13504                        if sel.is_empty() {
13505                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13506                        }
13507                    });
13508                });
13509            }
13510            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13511            let item = this.cut_common(false, window, cx);
13512            cx.write_to_clipboard(item);
13513        });
13514    }
13515
13516    pub fn move_to_start_of_paragraph(
13517        &mut self,
13518        _: &MoveToStartOfParagraph,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        if matches!(self.mode, EditorMode::SingleLine) {
13523            cx.propagate();
13524            return;
13525        }
13526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13527        self.change_selections(Default::default(), window, cx, |s| {
13528            s.move_with(|map, selection| {
13529                selection.collapse_to(
13530                    movement::start_of_paragraph(map, selection.head(), 1),
13531                    SelectionGoal::None,
13532                )
13533            });
13534        })
13535    }
13536
13537    pub fn move_to_end_of_paragraph(
13538        &mut self,
13539        _: &MoveToEndOfParagraph,
13540        window: &mut Window,
13541        cx: &mut Context<Self>,
13542    ) {
13543        if matches!(self.mode, EditorMode::SingleLine) {
13544            cx.propagate();
13545            return;
13546        }
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_with(|map, selection| {
13550                selection.collapse_to(
13551                    movement::end_of_paragraph(map, selection.head(), 1),
13552                    SelectionGoal::None,
13553                )
13554            });
13555        })
13556    }
13557
13558    pub fn select_to_start_of_paragraph(
13559        &mut self,
13560        _: &SelectToStartOfParagraph,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        if matches!(self.mode, EditorMode::SingleLine) {
13565            cx.propagate();
13566            return;
13567        }
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_heads_with(|map, head, _| {
13571                (
13572                    movement::start_of_paragraph(map, head, 1),
13573                    SelectionGoal::None,
13574                )
13575            });
13576        })
13577    }
13578
13579    pub fn select_to_end_of_paragraph(
13580        &mut self,
13581        _: &SelectToEndOfParagraph,
13582        window: &mut Window,
13583        cx: &mut Context<Self>,
13584    ) {
13585        if matches!(self.mode, EditorMode::SingleLine) {
13586            cx.propagate();
13587            return;
13588        }
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_heads_with(|map, head, _| {
13592                (
13593                    movement::end_of_paragraph(map, head, 1),
13594                    SelectionGoal::None,
13595                )
13596            });
13597        })
13598    }
13599
13600    pub fn move_to_start_of_excerpt(
13601        &mut self,
13602        _: &MoveToStartOfExcerpt,
13603        window: &mut Window,
13604        cx: &mut Context<Self>,
13605    ) {
13606        if matches!(self.mode, EditorMode::SingleLine) {
13607            cx.propagate();
13608            return;
13609        }
13610        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13611        self.change_selections(Default::default(), window, cx, |s| {
13612            s.move_with(|map, selection| {
13613                selection.collapse_to(
13614                    movement::start_of_excerpt(
13615                        map,
13616                        selection.head(),
13617                        workspace::searchable::Direction::Prev,
13618                    ),
13619                    SelectionGoal::None,
13620                )
13621            });
13622        })
13623    }
13624
13625    pub fn move_to_start_of_next_excerpt(
13626        &mut self,
13627        _: &MoveToStartOfNextExcerpt,
13628        window: &mut Window,
13629        cx: &mut Context<Self>,
13630    ) {
13631        if matches!(self.mode, EditorMode::SingleLine) {
13632            cx.propagate();
13633            return;
13634        }
13635
13636        self.change_selections(Default::default(), window, cx, |s| {
13637            s.move_with(|map, selection| {
13638                selection.collapse_to(
13639                    movement::start_of_excerpt(
13640                        map,
13641                        selection.head(),
13642                        workspace::searchable::Direction::Next,
13643                    ),
13644                    SelectionGoal::None,
13645                )
13646            });
13647        })
13648    }
13649
13650    pub fn move_to_end_of_excerpt(
13651        &mut self,
13652        _: &MoveToEndOfExcerpt,
13653        window: &mut Window,
13654        cx: &mut Context<Self>,
13655    ) {
13656        if matches!(self.mode, EditorMode::SingleLine) {
13657            cx.propagate();
13658            return;
13659        }
13660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13661        self.change_selections(Default::default(), window, cx, |s| {
13662            s.move_with(|map, selection| {
13663                selection.collapse_to(
13664                    movement::end_of_excerpt(
13665                        map,
13666                        selection.head(),
13667                        workspace::searchable::Direction::Next,
13668                    ),
13669                    SelectionGoal::None,
13670                )
13671            });
13672        })
13673    }
13674
13675    pub fn move_to_end_of_previous_excerpt(
13676        &mut self,
13677        _: &MoveToEndOfPreviousExcerpt,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        if matches!(self.mode, EditorMode::SingleLine) {
13682            cx.propagate();
13683            return;
13684        }
13685        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13686        self.change_selections(Default::default(), window, cx, |s| {
13687            s.move_with(|map, selection| {
13688                selection.collapse_to(
13689                    movement::end_of_excerpt(
13690                        map,
13691                        selection.head(),
13692                        workspace::searchable::Direction::Prev,
13693                    ),
13694                    SelectionGoal::None,
13695                )
13696            });
13697        })
13698    }
13699
13700    pub fn select_to_start_of_excerpt(
13701        &mut self,
13702        _: &SelectToStartOfExcerpt,
13703        window: &mut Window,
13704        cx: &mut Context<Self>,
13705    ) {
13706        if matches!(self.mode, EditorMode::SingleLine) {
13707            cx.propagate();
13708            return;
13709        }
13710        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13711        self.change_selections(Default::default(), window, cx, |s| {
13712            s.move_heads_with(|map, head, _| {
13713                (
13714                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13715                    SelectionGoal::None,
13716                )
13717            });
13718        })
13719    }
13720
13721    pub fn select_to_start_of_next_excerpt(
13722        &mut self,
13723        _: &SelectToStartOfNextExcerpt,
13724        window: &mut Window,
13725        cx: &mut Context<Self>,
13726    ) {
13727        if matches!(self.mode, EditorMode::SingleLine) {
13728            cx.propagate();
13729            return;
13730        }
13731        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13732        self.change_selections(Default::default(), window, cx, |s| {
13733            s.move_heads_with(|map, head, _| {
13734                (
13735                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13736                    SelectionGoal::None,
13737                )
13738            });
13739        })
13740    }
13741
13742    pub fn select_to_end_of_excerpt(
13743        &mut self,
13744        _: &SelectToEndOfExcerpt,
13745        window: &mut Window,
13746        cx: &mut Context<Self>,
13747    ) {
13748        if matches!(self.mode, EditorMode::SingleLine) {
13749            cx.propagate();
13750            return;
13751        }
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_heads_with(|map, head, _| {
13755                (
13756                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13757                    SelectionGoal::None,
13758                )
13759            });
13760        })
13761    }
13762
13763    pub fn select_to_end_of_previous_excerpt(
13764        &mut self,
13765        _: &SelectToEndOfPreviousExcerpt,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
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::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn move_to_beginning(
13785        &mut self,
13786        _: &MoveToBeginning,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.select_ranges(vec![0..0]);
13797        });
13798    }
13799
13800    pub fn select_to_beginning(
13801        &mut self,
13802        _: &SelectToBeginning,
13803        window: &mut Window,
13804        cx: &mut Context<Self>,
13805    ) {
13806        let mut selection = self.selections.last::<Point>(cx);
13807        selection.set_head(Point::zero(), SelectionGoal::None);
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13809        self.change_selections(Default::default(), window, cx, |s| {
13810            s.select(vec![selection]);
13811        });
13812    }
13813
13814    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13815        if matches!(self.mode, EditorMode::SingleLine) {
13816            cx.propagate();
13817            return;
13818        }
13819        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13820        let cursor = self.buffer.read(cx).read(cx).len();
13821        self.change_selections(Default::default(), window, cx, |s| {
13822            s.select_ranges(vec![cursor..cursor])
13823        });
13824    }
13825
13826    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13827        self.nav_history = nav_history;
13828    }
13829
13830    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13831        self.nav_history.as_ref()
13832    }
13833
13834    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13835        self.push_to_nav_history(
13836            self.selections.newest_anchor().head(),
13837            None,
13838            false,
13839            true,
13840            cx,
13841        );
13842    }
13843
13844    fn push_to_nav_history(
13845        &mut self,
13846        cursor_anchor: Anchor,
13847        new_position: Option<Point>,
13848        is_deactivate: bool,
13849        always: bool,
13850        cx: &mut Context<Self>,
13851    ) {
13852        if let Some(nav_history) = self.nav_history.as_mut() {
13853            let buffer = self.buffer.read(cx).read(cx);
13854            let cursor_position = cursor_anchor.to_point(&buffer);
13855            let scroll_state = self.scroll_manager.anchor();
13856            let scroll_top_row = scroll_state.top_row(&buffer);
13857            drop(buffer);
13858
13859            if let Some(new_position) = new_position {
13860                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13861                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13862                    return;
13863                }
13864            }
13865
13866            nav_history.push(
13867                Some(NavigationData {
13868                    cursor_anchor,
13869                    cursor_position,
13870                    scroll_anchor: scroll_state,
13871                    scroll_top_row,
13872                }),
13873                cx,
13874            );
13875            cx.emit(EditorEvent::PushedToNavHistory {
13876                anchor: cursor_anchor,
13877                is_deactivate,
13878            })
13879        }
13880    }
13881
13882    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13884        let buffer = self.buffer.read(cx).snapshot(cx);
13885        let mut selection = self.selections.first::<usize>(cx);
13886        selection.set_head(buffer.len(), SelectionGoal::None);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.select(vec![selection]);
13889        });
13890    }
13891
13892    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13894        let end = self.buffer.read(cx).read(cx).len();
13895        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13896            s.select_ranges(vec![0..end]);
13897        });
13898    }
13899
13900    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13902        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13903        let mut selections = self.selections.all::<Point>(cx);
13904        let max_point = display_map.buffer_snapshot.max_point();
13905        for selection in &mut selections {
13906            let rows = selection.spanned_rows(true, &display_map);
13907            selection.start = Point::new(rows.start.0, 0);
13908            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13909            selection.reversed = false;
13910        }
13911        self.change_selections(Default::default(), window, cx, |s| {
13912            s.select(selections);
13913        });
13914    }
13915
13916    pub fn split_selection_into_lines(
13917        &mut self,
13918        action: &SplitSelectionIntoLines,
13919        window: &mut Window,
13920        cx: &mut Context<Self>,
13921    ) {
13922        let selections = self
13923            .selections
13924            .all::<Point>(cx)
13925            .into_iter()
13926            .map(|selection| selection.start..selection.end)
13927            .collect::<Vec<_>>();
13928        self.unfold_ranges(&selections, true, true, cx);
13929
13930        let mut new_selection_ranges = Vec::new();
13931        {
13932            let buffer = self.buffer.read(cx).read(cx);
13933            for selection in selections {
13934                for row in selection.start.row..selection.end.row {
13935                    let line_start = Point::new(row, 0);
13936                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13937
13938                    if action.keep_selections {
13939                        // Keep the selection range for each line
13940                        let selection_start = if row == selection.start.row {
13941                            selection.start
13942                        } else {
13943                            line_start
13944                        };
13945                        new_selection_ranges.push(selection_start..line_end);
13946                    } else {
13947                        // Collapse to cursor at end of line
13948                        new_selection_ranges.push(line_end..line_end);
13949                    }
13950                }
13951
13952                let is_multiline_selection = selection.start.row != selection.end.row;
13953                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13954                // so this action feels more ergonomic when paired with other selection operations
13955                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13956                if !should_skip_last {
13957                    if action.keep_selections {
13958                        if is_multiline_selection {
13959                            let line_start = Point::new(selection.end.row, 0);
13960                            new_selection_ranges.push(line_start..selection.end);
13961                        } else {
13962                            new_selection_ranges.push(selection.start..selection.end);
13963                        }
13964                    } else {
13965                        new_selection_ranges.push(selection.end..selection.end);
13966                    }
13967                }
13968            }
13969        }
13970        self.change_selections(Default::default(), window, cx, |s| {
13971            s.select_ranges(new_selection_ranges);
13972        });
13973    }
13974
13975    pub fn add_selection_above(
13976        &mut self,
13977        _: &AddSelectionAbove,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        self.add_selection(true, window, cx);
13982    }
13983
13984    pub fn add_selection_below(
13985        &mut self,
13986        _: &AddSelectionBelow,
13987        window: &mut Window,
13988        cx: &mut Context<Self>,
13989    ) {
13990        self.add_selection(false, window, cx);
13991    }
13992
13993    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13994        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13995
13996        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13997        let all_selections = self.selections.all::<Point>(cx);
13998        let text_layout_details = self.text_layout_details(window);
13999
14000        let (mut columnar_selections, new_selections_to_columnarize) = {
14001            if let Some(state) = self.add_selections_state.as_ref() {
14002                let columnar_selection_ids: HashSet<_> = state
14003                    .groups
14004                    .iter()
14005                    .flat_map(|group| group.stack.iter())
14006                    .copied()
14007                    .collect();
14008
14009                all_selections
14010                    .into_iter()
14011                    .partition(|s| columnar_selection_ids.contains(&s.id))
14012            } else {
14013                (Vec::new(), all_selections)
14014            }
14015        };
14016
14017        let mut state = self
14018            .add_selections_state
14019            .take()
14020            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14021
14022        for selection in new_selections_to_columnarize {
14023            let range = selection.display_range(&display_map).sorted();
14024            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14025            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14026            let positions = start_x.min(end_x)..start_x.max(end_x);
14027            let mut stack = Vec::new();
14028            for row in range.start.row().0..=range.end.row().0 {
14029                if let Some(selection) = self.selections.build_columnar_selection(
14030                    &display_map,
14031                    DisplayRow(row),
14032                    &positions,
14033                    selection.reversed,
14034                    &text_layout_details,
14035                ) {
14036                    stack.push(selection.id);
14037                    columnar_selections.push(selection);
14038                }
14039            }
14040            if !stack.is_empty() {
14041                if above {
14042                    stack.reverse();
14043                }
14044                state.groups.push(AddSelectionsGroup { above, stack });
14045            }
14046        }
14047
14048        let mut final_selections = Vec::new();
14049        let end_row = if above {
14050            DisplayRow(0)
14051        } else {
14052            display_map.max_point().row()
14053        };
14054
14055        let mut last_added_item_per_group = HashMap::default();
14056        for group in state.groups.iter_mut() {
14057            if let Some(last_id) = group.stack.last() {
14058                last_added_item_per_group.insert(*last_id, group);
14059            }
14060        }
14061
14062        for selection in columnar_selections {
14063            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14064                if above == group.above {
14065                    let range = selection.display_range(&display_map).sorted();
14066                    debug_assert_eq!(range.start.row(), range.end.row());
14067                    let mut row = range.start.row();
14068                    let positions =
14069                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14070                            px(start)..px(end)
14071                        } else {
14072                            let start_x =
14073                                display_map.x_for_display_point(range.start, &text_layout_details);
14074                            let end_x =
14075                                display_map.x_for_display_point(range.end, &text_layout_details);
14076                            start_x.min(end_x)..start_x.max(end_x)
14077                        };
14078
14079                    let mut maybe_new_selection = None;
14080                    while row != end_row {
14081                        if above {
14082                            row.0 -= 1;
14083                        } else {
14084                            row.0 += 1;
14085                        }
14086                        if let Some(new_selection) = self.selections.build_columnar_selection(
14087                            &display_map,
14088                            row,
14089                            &positions,
14090                            selection.reversed,
14091                            &text_layout_details,
14092                        ) {
14093                            maybe_new_selection = Some(new_selection);
14094                            break;
14095                        }
14096                    }
14097
14098                    if let Some(new_selection) = maybe_new_selection {
14099                        group.stack.push(new_selection.id);
14100                        if above {
14101                            final_selections.push(new_selection);
14102                            final_selections.push(selection);
14103                        } else {
14104                            final_selections.push(selection);
14105                            final_selections.push(new_selection);
14106                        }
14107                    } else {
14108                        final_selections.push(selection);
14109                    }
14110                } else {
14111                    group.stack.pop();
14112                }
14113            } else {
14114                final_selections.push(selection);
14115            }
14116        }
14117
14118        self.change_selections(Default::default(), window, cx, |s| {
14119            s.select(final_selections);
14120        });
14121
14122        let final_selection_ids: HashSet<_> = self
14123            .selections
14124            .all::<Point>(cx)
14125            .iter()
14126            .map(|s| s.id)
14127            .collect();
14128        state.groups.retain_mut(|group| {
14129            // selections might get merged above so we remove invalid items from stacks
14130            group.stack.retain(|id| final_selection_ids.contains(id));
14131
14132            // single selection in stack can be treated as initial state
14133            group.stack.len() > 1
14134        });
14135
14136        if !state.groups.is_empty() {
14137            self.add_selections_state = Some(state);
14138        }
14139    }
14140
14141    fn select_match_ranges(
14142        &mut self,
14143        range: Range<usize>,
14144        reversed: bool,
14145        replace_newest: bool,
14146        auto_scroll: Option<Autoscroll>,
14147        window: &mut Window,
14148        cx: &mut Context<Editor>,
14149    ) {
14150        self.unfold_ranges(
14151            std::slice::from_ref(&range),
14152            false,
14153            auto_scroll.is_some(),
14154            cx,
14155        );
14156        let effects = if let Some(scroll) = auto_scroll {
14157            SelectionEffects::scroll(scroll)
14158        } else {
14159            SelectionEffects::no_scroll()
14160        };
14161        self.change_selections(effects, window, cx, |s| {
14162            if replace_newest {
14163                s.delete(s.newest_anchor().id);
14164            }
14165            if reversed {
14166                s.insert_range(range.end..range.start);
14167            } else {
14168                s.insert_range(range);
14169            }
14170        });
14171    }
14172
14173    pub fn select_next_match_internal(
14174        &mut self,
14175        display_map: &DisplaySnapshot,
14176        replace_newest: bool,
14177        autoscroll: Option<Autoscroll>,
14178        window: &mut Window,
14179        cx: &mut Context<Self>,
14180    ) -> Result<()> {
14181        let buffer = &display_map.buffer_snapshot;
14182        let mut selections = self.selections.all::<usize>(cx);
14183        if let Some(mut select_next_state) = self.select_next_state.take() {
14184            let query = &select_next_state.query;
14185            if !select_next_state.done {
14186                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14187                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14188                let mut next_selected_range = None;
14189
14190                let bytes_after_last_selection =
14191                    buffer.bytes_in_range(last_selection.end..buffer.len());
14192                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14193                let query_matches = query
14194                    .stream_find_iter(bytes_after_last_selection)
14195                    .map(|result| (last_selection.end, result))
14196                    .chain(
14197                        query
14198                            .stream_find_iter(bytes_before_first_selection)
14199                            .map(|result| (0, result)),
14200                    );
14201
14202                for (start_offset, query_match) in query_matches {
14203                    let query_match = query_match.unwrap(); // can only fail due to I/O
14204                    let offset_range =
14205                        start_offset + query_match.start()..start_offset + query_match.end();
14206
14207                    if !select_next_state.wordwise
14208                        || (!buffer.is_inside_word(offset_range.start, false)
14209                            && !buffer.is_inside_word(offset_range.end, false))
14210                    {
14211                        // TODO: This is n^2, because we might check all the selections
14212                        if !selections
14213                            .iter()
14214                            .any(|selection| selection.range().overlaps(&offset_range))
14215                        {
14216                            next_selected_range = Some(offset_range);
14217                            break;
14218                        }
14219                    }
14220                }
14221
14222                if let Some(next_selected_range) = next_selected_range {
14223                    self.select_match_ranges(
14224                        next_selected_range,
14225                        last_selection.reversed,
14226                        replace_newest,
14227                        autoscroll,
14228                        window,
14229                        cx,
14230                    );
14231                } else {
14232                    select_next_state.done = true;
14233                }
14234            }
14235
14236            self.select_next_state = Some(select_next_state);
14237        } else {
14238            let mut only_carets = true;
14239            let mut same_text_selected = true;
14240            let mut selected_text = None;
14241
14242            let mut selections_iter = selections.iter().peekable();
14243            while let Some(selection) = selections_iter.next() {
14244                if selection.start != selection.end {
14245                    only_carets = false;
14246                }
14247
14248                if same_text_selected {
14249                    if selected_text.is_none() {
14250                        selected_text =
14251                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14252                    }
14253
14254                    if let Some(next_selection) = selections_iter.peek() {
14255                        if next_selection.range().len() == selection.range().len() {
14256                            let next_selected_text = buffer
14257                                .text_for_range(next_selection.range())
14258                                .collect::<String>();
14259                            if Some(next_selected_text) != selected_text {
14260                                same_text_selected = false;
14261                                selected_text = None;
14262                            }
14263                        } else {
14264                            same_text_selected = false;
14265                            selected_text = None;
14266                        }
14267                    }
14268                }
14269            }
14270
14271            if only_carets {
14272                for selection in &mut selections {
14273                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14274                    selection.start = word_range.start;
14275                    selection.end = word_range.end;
14276                    selection.goal = SelectionGoal::None;
14277                    selection.reversed = false;
14278                    self.select_match_ranges(
14279                        selection.start..selection.end,
14280                        selection.reversed,
14281                        replace_newest,
14282                        autoscroll,
14283                        window,
14284                        cx,
14285                    );
14286                }
14287
14288                if selections.len() == 1 {
14289                    let selection = selections
14290                        .last()
14291                        .expect("ensured that there's only one selection");
14292                    let query = buffer
14293                        .text_for_range(selection.start..selection.end)
14294                        .collect::<String>();
14295                    let is_empty = query.is_empty();
14296                    let select_state = SelectNextState {
14297                        query: AhoCorasick::new(&[query])?,
14298                        wordwise: true,
14299                        done: is_empty,
14300                    };
14301                    self.select_next_state = Some(select_state);
14302                } else {
14303                    self.select_next_state = None;
14304                }
14305            } else if let Some(selected_text) = selected_text {
14306                self.select_next_state = Some(SelectNextState {
14307                    query: AhoCorasick::new(&[selected_text])?,
14308                    wordwise: false,
14309                    done: false,
14310                });
14311                self.select_next_match_internal(
14312                    display_map,
14313                    replace_newest,
14314                    autoscroll,
14315                    window,
14316                    cx,
14317                )?;
14318            }
14319        }
14320        Ok(())
14321    }
14322
14323    pub fn select_all_matches(
14324        &mut self,
14325        _action: &SelectAllMatches,
14326        window: &mut Window,
14327        cx: &mut Context<Self>,
14328    ) -> Result<()> {
14329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14330
14331        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14332
14333        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14334        let Some(select_next_state) = self.select_next_state.as_mut() else {
14335            return Ok(());
14336        };
14337        if select_next_state.done {
14338            return Ok(());
14339        }
14340
14341        let mut new_selections = Vec::new();
14342
14343        let reversed = self.selections.oldest::<usize>(cx).reversed;
14344        let buffer = &display_map.buffer_snapshot;
14345        let query_matches = select_next_state
14346            .query
14347            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14348
14349        for query_match in query_matches.into_iter() {
14350            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14351            let offset_range = if reversed {
14352                query_match.end()..query_match.start()
14353            } else {
14354                query_match.start()..query_match.end()
14355            };
14356
14357            if !select_next_state.wordwise
14358                || (!buffer.is_inside_word(offset_range.start, false)
14359                    && !buffer.is_inside_word(offset_range.end, false))
14360            {
14361                new_selections.push(offset_range.start..offset_range.end);
14362            }
14363        }
14364
14365        select_next_state.done = true;
14366
14367        if new_selections.is_empty() {
14368            log::error!("bug: new_selections is empty in select_all_matches");
14369            return Ok(());
14370        }
14371
14372        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14373        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14374            selections.select_ranges(new_selections)
14375        });
14376
14377        Ok(())
14378    }
14379
14380    pub fn select_next(
14381        &mut self,
14382        action: &SelectNext,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) -> Result<()> {
14386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14388        self.select_next_match_internal(
14389            &display_map,
14390            action.replace_newest,
14391            Some(Autoscroll::newest()),
14392            window,
14393            cx,
14394        )?;
14395        Ok(())
14396    }
14397
14398    pub fn select_previous(
14399        &mut self,
14400        action: &SelectPrevious,
14401        window: &mut Window,
14402        cx: &mut Context<Self>,
14403    ) -> Result<()> {
14404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14405        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14406        let buffer = &display_map.buffer_snapshot;
14407        let mut selections = self.selections.all::<usize>(cx);
14408        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14409            let query = &select_prev_state.query;
14410            if !select_prev_state.done {
14411                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14412                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14413                let mut next_selected_range = None;
14414                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14415                let bytes_before_last_selection =
14416                    buffer.reversed_bytes_in_range(0..last_selection.start);
14417                let bytes_after_first_selection =
14418                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14419                let query_matches = query
14420                    .stream_find_iter(bytes_before_last_selection)
14421                    .map(|result| (last_selection.start, result))
14422                    .chain(
14423                        query
14424                            .stream_find_iter(bytes_after_first_selection)
14425                            .map(|result| (buffer.len(), result)),
14426                    );
14427                for (end_offset, query_match) in query_matches {
14428                    let query_match = query_match.unwrap(); // can only fail due to I/O
14429                    let offset_range =
14430                        end_offset - query_match.end()..end_offset - query_match.start();
14431
14432                    if !select_prev_state.wordwise
14433                        || (!buffer.is_inside_word(offset_range.start, false)
14434                            && !buffer.is_inside_word(offset_range.end, false))
14435                    {
14436                        next_selected_range = Some(offset_range);
14437                        break;
14438                    }
14439                }
14440
14441                if let Some(next_selected_range) = next_selected_range {
14442                    self.select_match_ranges(
14443                        next_selected_range,
14444                        last_selection.reversed,
14445                        action.replace_newest,
14446                        Some(Autoscroll::newest()),
14447                        window,
14448                        cx,
14449                    );
14450                } else {
14451                    select_prev_state.done = true;
14452                }
14453            }
14454
14455            self.select_prev_state = Some(select_prev_state);
14456        } else {
14457            let mut only_carets = true;
14458            let mut same_text_selected = true;
14459            let mut selected_text = None;
14460
14461            let mut selections_iter = selections.iter().peekable();
14462            while let Some(selection) = selections_iter.next() {
14463                if selection.start != selection.end {
14464                    only_carets = false;
14465                }
14466
14467                if same_text_selected {
14468                    if selected_text.is_none() {
14469                        selected_text =
14470                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14471                    }
14472
14473                    if let Some(next_selection) = selections_iter.peek() {
14474                        if next_selection.range().len() == selection.range().len() {
14475                            let next_selected_text = buffer
14476                                .text_for_range(next_selection.range())
14477                                .collect::<String>();
14478                            if Some(next_selected_text) != selected_text {
14479                                same_text_selected = false;
14480                                selected_text = None;
14481                            }
14482                        } else {
14483                            same_text_selected = false;
14484                            selected_text = None;
14485                        }
14486                    }
14487                }
14488            }
14489
14490            if only_carets {
14491                for selection in &mut selections {
14492                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14493                    selection.start = word_range.start;
14494                    selection.end = word_range.end;
14495                    selection.goal = SelectionGoal::None;
14496                    selection.reversed = false;
14497                    self.select_match_ranges(
14498                        selection.start..selection.end,
14499                        selection.reversed,
14500                        action.replace_newest,
14501                        Some(Autoscroll::newest()),
14502                        window,
14503                        cx,
14504                    );
14505                }
14506                if selections.len() == 1 {
14507                    let selection = selections
14508                        .last()
14509                        .expect("ensured that there's only one selection");
14510                    let query = buffer
14511                        .text_for_range(selection.start..selection.end)
14512                        .collect::<String>();
14513                    let is_empty = query.is_empty();
14514                    let select_state = SelectNextState {
14515                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14516                        wordwise: true,
14517                        done: is_empty,
14518                    };
14519                    self.select_prev_state = Some(select_state);
14520                } else {
14521                    self.select_prev_state = None;
14522                }
14523            } else if let Some(selected_text) = selected_text {
14524                self.select_prev_state = Some(SelectNextState {
14525                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14526                    wordwise: false,
14527                    done: false,
14528                });
14529                self.select_previous(action, window, cx)?;
14530            }
14531        }
14532        Ok(())
14533    }
14534
14535    pub fn find_next_match(
14536        &mut self,
14537        _: &FindNextMatch,
14538        window: &mut Window,
14539        cx: &mut Context<Self>,
14540    ) -> Result<()> {
14541        let selections = self.selections.disjoint_anchors();
14542        match selections.first() {
14543            Some(first) if selections.len() >= 2 => {
14544                self.change_selections(Default::default(), window, cx, |s| {
14545                    s.select_ranges([first.range()]);
14546                });
14547            }
14548            _ => self.select_next(
14549                &SelectNext {
14550                    replace_newest: true,
14551                },
14552                window,
14553                cx,
14554            )?,
14555        }
14556        Ok(())
14557    }
14558
14559    pub fn find_previous_match(
14560        &mut self,
14561        _: &FindPreviousMatch,
14562        window: &mut Window,
14563        cx: &mut Context<Self>,
14564    ) -> Result<()> {
14565        let selections = self.selections.disjoint_anchors();
14566        match selections.last() {
14567            Some(last) if selections.len() >= 2 => {
14568                self.change_selections(Default::default(), window, cx, |s| {
14569                    s.select_ranges([last.range()]);
14570                });
14571            }
14572            _ => self.select_previous(
14573                &SelectPrevious {
14574                    replace_newest: true,
14575                },
14576                window,
14577                cx,
14578            )?,
14579        }
14580        Ok(())
14581    }
14582
14583    pub fn toggle_comments(
14584        &mut self,
14585        action: &ToggleComments,
14586        window: &mut Window,
14587        cx: &mut Context<Self>,
14588    ) {
14589        if self.read_only(cx) {
14590            return;
14591        }
14592        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14593        let text_layout_details = &self.text_layout_details(window);
14594        self.transact(window, cx, |this, window, cx| {
14595            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14596            let mut edits = Vec::new();
14597            let mut selection_edit_ranges = Vec::new();
14598            let mut last_toggled_row = None;
14599            let snapshot = this.buffer.read(cx).read(cx);
14600            let empty_str: Arc<str> = Arc::default();
14601            let mut suffixes_inserted = Vec::new();
14602            let ignore_indent = action.ignore_indent;
14603
14604            fn comment_prefix_range(
14605                snapshot: &MultiBufferSnapshot,
14606                row: MultiBufferRow,
14607                comment_prefix: &str,
14608                comment_prefix_whitespace: &str,
14609                ignore_indent: bool,
14610            ) -> Range<Point> {
14611                let indent_size = if ignore_indent {
14612                    0
14613                } else {
14614                    snapshot.indent_size_for_line(row).len
14615                };
14616
14617                let start = Point::new(row.0, indent_size);
14618
14619                let mut line_bytes = snapshot
14620                    .bytes_in_range(start..snapshot.max_point())
14621                    .flatten()
14622                    .copied();
14623
14624                // If this line currently begins with the line comment prefix, then record
14625                // the range containing the prefix.
14626                if line_bytes
14627                    .by_ref()
14628                    .take(comment_prefix.len())
14629                    .eq(comment_prefix.bytes())
14630                {
14631                    // Include any whitespace that matches the comment prefix.
14632                    let matching_whitespace_len = line_bytes
14633                        .zip(comment_prefix_whitespace.bytes())
14634                        .take_while(|(a, b)| a == b)
14635                        .count() as u32;
14636                    let end = Point::new(
14637                        start.row,
14638                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14639                    );
14640                    start..end
14641                } else {
14642                    start..start
14643                }
14644            }
14645
14646            fn comment_suffix_range(
14647                snapshot: &MultiBufferSnapshot,
14648                row: MultiBufferRow,
14649                comment_suffix: &str,
14650                comment_suffix_has_leading_space: bool,
14651            ) -> Range<Point> {
14652                let end = Point::new(row.0, snapshot.line_len(row));
14653                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14654
14655                let mut line_end_bytes = snapshot
14656                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14657                    .flatten()
14658                    .copied();
14659
14660                let leading_space_len = if suffix_start_column > 0
14661                    && line_end_bytes.next() == Some(b' ')
14662                    && comment_suffix_has_leading_space
14663                {
14664                    1
14665                } else {
14666                    0
14667                };
14668
14669                // If this line currently begins with the line comment prefix, then record
14670                // the range containing the prefix.
14671                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14672                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14673                    start..end
14674                } else {
14675                    end..end
14676                }
14677            }
14678
14679            // TODO: Handle selections that cross excerpts
14680            for selection in &mut selections {
14681                let start_column = snapshot
14682                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14683                    .len;
14684                let language = if let Some(language) =
14685                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14686                {
14687                    language
14688                } else {
14689                    continue;
14690                };
14691
14692                selection_edit_ranges.clear();
14693
14694                // If multiple selections contain a given row, avoid processing that
14695                // row more than once.
14696                let mut start_row = MultiBufferRow(selection.start.row);
14697                if last_toggled_row == Some(start_row) {
14698                    start_row = start_row.next_row();
14699                }
14700                let end_row =
14701                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14702                        MultiBufferRow(selection.end.row - 1)
14703                    } else {
14704                        MultiBufferRow(selection.end.row)
14705                    };
14706                last_toggled_row = Some(end_row);
14707
14708                if start_row > end_row {
14709                    continue;
14710                }
14711
14712                // If the language has line comments, toggle those.
14713                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14714
14715                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14716                if ignore_indent {
14717                    full_comment_prefixes = full_comment_prefixes
14718                        .into_iter()
14719                        .map(|s| Arc::from(s.trim_end()))
14720                        .collect();
14721                }
14722
14723                if !full_comment_prefixes.is_empty() {
14724                    let first_prefix = full_comment_prefixes
14725                        .first()
14726                        .expect("prefixes is non-empty");
14727                    let prefix_trimmed_lengths = full_comment_prefixes
14728                        .iter()
14729                        .map(|p| p.trim_end_matches(' ').len())
14730                        .collect::<SmallVec<[usize; 4]>>();
14731
14732                    let mut all_selection_lines_are_comments = true;
14733
14734                    for row in start_row.0..=end_row.0 {
14735                        let row = MultiBufferRow(row);
14736                        if start_row < end_row && snapshot.is_line_blank(row) {
14737                            continue;
14738                        }
14739
14740                        let prefix_range = full_comment_prefixes
14741                            .iter()
14742                            .zip(prefix_trimmed_lengths.iter().copied())
14743                            .map(|(prefix, trimmed_prefix_len)| {
14744                                comment_prefix_range(
14745                                    snapshot.deref(),
14746                                    row,
14747                                    &prefix[..trimmed_prefix_len],
14748                                    &prefix[trimmed_prefix_len..],
14749                                    ignore_indent,
14750                                )
14751                            })
14752                            .max_by_key(|range| range.end.column - range.start.column)
14753                            .expect("prefixes is non-empty");
14754
14755                        if prefix_range.is_empty() {
14756                            all_selection_lines_are_comments = false;
14757                        }
14758
14759                        selection_edit_ranges.push(prefix_range);
14760                    }
14761
14762                    if all_selection_lines_are_comments {
14763                        edits.extend(
14764                            selection_edit_ranges
14765                                .iter()
14766                                .cloned()
14767                                .map(|range| (range, empty_str.clone())),
14768                        );
14769                    } else {
14770                        let min_column = selection_edit_ranges
14771                            .iter()
14772                            .map(|range| range.start.column)
14773                            .min()
14774                            .unwrap_or(0);
14775                        edits.extend(selection_edit_ranges.iter().map(|range| {
14776                            let position = Point::new(range.start.row, min_column);
14777                            (position..position, first_prefix.clone())
14778                        }));
14779                    }
14780                } else if let Some(BlockCommentConfig {
14781                    start: full_comment_prefix,
14782                    end: comment_suffix,
14783                    ..
14784                }) = language.block_comment()
14785                {
14786                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14787                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14788                    let prefix_range = comment_prefix_range(
14789                        snapshot.deref(),
14790                        start_row,
14791                        comment_prefix,
14792                        comment_prefix_whitespace,
14793                        ignore_indent,
14794                    );
14795                    let suffix_range = comment_suffix_range(
14796                        snapshot.deref(),
14797                        end_row,
14798                        comment_suffix.trim_start_matches(' '),
14799                        comment_suffix.starts_with(' '),
14800                    );
14801
14802                    if prefix_range.is_empty() || suffix_range.is_empty() {
14803                        edits.push((
14804                            prefix_range.start..prefix_range.start,
14805                            full_comment_prefix.clone(),
14806                        ));
14807                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14808                        suffixes_inserted.push((end_row, comment_suffix.len()));
14809                    } else {
14810                        edits.push((prefix_range, empty_str.clone()));
14811                        edits.push((suffix_range, empty_str.clone()));
14812                    }
14813                } else {
14814                    continue;
14815                }
14816            }
14817
14818            drop(snapshot);
14819            this.buffer.update(cx, |buffer, cx| {
14820                buffer.edit(edits, None, cx);
14821            });
14822
14823            // Adjust selections so that they end before any comment suffixes that
14824            // were inserted.
14825            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14826            let mut selections = this.selections.all::<Point>(cx);
14827            let snapshot = this.buffer.read(cx).read(cx);
14828            for selection in &mut selections {
14829                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14830                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14831                        Ordering::Less => {
14832                            suffixes_inserted.next();
14833                            continue;
14834                        }
14835                        Ordering::Greater => break,
14836                        Ordering::Equal => {
14837                            if selection.end.column == snapshot.line_len(row) {
14838                                if selection.is_empty() {
14839                                    selection.start.column -= suffix_len as u32;
14840                                }
14841                                selection.end.column -= suffix_len as u32;
14842                            }
14843                            break;
14844                        }
14845                    }
14846                }
14847            }
14848
14849            drop(snapshot);
14850            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14851
14852            let selections = this.selections.all::<Point>(cx);
14853            let selections_on_single_row = selections.windows(2).all(|selections| {
14854                selections[0].start.row == selections[1].start.row
14855                    && selections[0].end.row == selections[1].end.row
14856                    && selections[0].start.row == selections[0].end.row
14857            });
14858            let selections_selecting = selections
14859                .iter()
14860                .any(|selection| selection.start != selection.end);
14861            let advance_downwards = action.advance_downwards
14862                && selections_on_single_row
14863                && !selections_selecting
14864                && !matches!(this.mode, EditorMode::SingleLine);
14865
14866            if advance_downwards {
14867                let snapshot = this.buffer.read(cx).snapshot(cx);
14868
14869                this.change_selections(Default::default(), window, cx, |s| {
14870                    s.move_cursors_with(|display_snapshot, display_point, _| {
14871                        let mut point = display_point.to_point(display_snapshot);
14872                        point.row += 1;
14873                        point = snapshot.clip_point(point, Bias::Left);
14874                        let display_point = point.to_display_point(display_snapshot);
14875                        let goal = SelectionGoal::HorizontalPosition(
14876                            display_snapshot
14877                                .x_for_display_point(display_point, text_layout_details)
14878                                .into(),
14879                        );
14880                        (display_point, goal)
14881                    })
14882                });
14883            }
14884        });
14885    }
14886
14887    pub fn select_enclosing_symbol(
14888        &mut self,
14889        _: &SelectEnclosingSymbol,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) {
14893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14894
14895        let buffer = self.buffer.read(cx).snapshot(cx);
14896        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14897
14898        fn update_selection(
14899            selection: &Selection<usize>,
14900            buffer_snap: &MultiBufferSnapshot,
14901        ) -> Option<Selection<usize>> {
14902            let cursor = selection.head();
14903            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14904            for symbol in symbols.iter().rev() {
14905                let start = symbol.range.start.to_offset(buffer_snap);
14906                let end = symbol.range.end.to_offset(buffer_snap);
14907                let new_range = start..end;
14908                if start < selection.start || end > selection.end {
14909                    return Some(Selection {
14910                        id: selection.id,
14911                        start: new_range.start,
14912                        end: new_range.end,
14913                        goal: SelectionGoal::None,
14914                        reversed: selection.reversed,
14915                    });
14916                }
14917            }
14918            None
14919        }
14920
14921        let mut selected_larger_symbol = false;
14922        let new_selections = old_selections
14923            .iter()
14924            .map(|selection| match update_selection(selection, &buffer) {
14925                Some(new_selection) => {
14926                    if new_selection.range() != selection.range() {
14927                        selected_larger_symbol = true;
14928                    }
14929                    new_selection
14930                }
14931                None => selection.clone(),
14932            })
14933            .collect::<Vec<_>>();
14934
14935        if selected_larger_symbol {
14936            self.change_selections(Default::default(), window, cx, |s| {
14937                s.select(new_selections);
14938            });
14939        }
14940    }
14941
14942    pub fn select_larger_syntax_node(
14943        &mut self,
14944        _: &SelectLargerSyntaxNode,
14945        window: &mut Window,
14946        cx: &mut Context<Self>,
14947    ) {
14948        let Some(visible_row_count) = self.visible_row_count() else {
14949            return;
14950        };
14951        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14952        if old_selections.is_empty() {
14953            return;
14954        }
14955
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957
14958        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14959        let buffer = self.buffer.read(cx).snapshot(cx);
14960
14961        let mut selected_larger_node = false;
14962        let mut new_selections = old_selections
14963            .iter()
14964            .map(|selection| {
14965                let old_range = selection.start..selection.end;
14966
14967                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14968                    // manually select word at selection
14969                    if ["string_content", "inline"].contains(&node.kind()) {
14970                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14971                        // ignore if word is already selected
14972                        if !word_range.is_empty() && old_range != word_range {
14973                            let (last_word_range, _) =
14974                                buffer.surrounding_word(old_range.end, false);
14975                            // only select word if start and end point belongs to same word
14976                            if word_range == last_word_range {
14977                                selected_larger_node = true;
14978                                return Selection {
14979                                    id: selection.id,
14980                                    start: word_range.start,
14981                                    end: word_range.end,
14982                                    goal: SelectionGoal::None,
14983                                    reversed: selection.reversed,
14984                                };
14985                            }
14986                        }
14987                    }
14988                }
14989
14990                let mut new_range = old_range.clone();
14991                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
14992                    new_range = range;
14993                    if !node.is_named() {
14994                        continue;
14995                    }
14996                    if !display_map.intersects_fold(new_range.start)
14997                        && !display_map.intersects_fold(new_range.end)
14998                    {
14999                        break;
15000                    }
15001                }
15002
15003                selected_larger_node |= new_range != old_range;
15004                Selection {
15005                    id: selection.id,
15006                    start: new_range.start,
15007                    end: new_range.end,
15008                    goal: SelectionGoal::None,
15009                    reversed: selection.reversed,
15010                }
15011            })
15012            .collect::<Vec<_>>();
15013
15014        if !selected_larger_node {
15015            return; // don't put this call in the history
15016        }
15017
15018        // scroll based on transformation done to the last selection created by the user
15019        let (last_old, last_new) = old_selections
15020            .last()
15021            .zip(new_selections.last().cloned())
15022            .expect("old_selections isn't empty");
15023
15024        // revert selection
15025        let is_selection_reversed = {
15026            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15027            new_selections.last_mut().expect("checked above").reversed =
15028                should_newest_selection_be_reversed;
15029            should_newest_selection_be_reversed
15030        };
15031
15032        if selected_larger_node {
15033            self.select_syntax_node_history.disable_clearing = true;
15034            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15035                s.select(new_selections.clone());
15036            });
15037            self.select_syntax_node_history.disable_clearing = false;
15038        }
15039
15040        let start_row = last_new.start.to_display_point(&display_map).row().0;
15041        let end_row = last_new.end.to_display_point(&display_map).row().0;
15042        let selection_height = end_row - start_row + 1;
15043        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15044
15045        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15046        let scroll_behavior = if fits_on_the_screen {
15047            self.request_autoscroll(Autoscroll::fit(), cx);
15048            SelectSyntaxNodeScrollBehavior::FitSelection
15049        } else if is_selection_reversed {
15050            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15051            SelectSyntaxNodeScrollBehavior::CursorTop
15052        } else {
15053            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15054            SelectSyntaxNodeScrollBehavior::CursorBottom
15055        };
15056
15057        self.select_syntax_node_history.push((
15058            old_selections,
15059            scroll_behavior,
15060            is_selection_reversed,
15061        ));
15062    }
15063
15064    pub fn select_smaller_syntax_node(
15065        &mut self,
15066        _: &SelectSmallerSyntaxNode,
15067        window: &mut Window,
15068        cx: &mut Context<Self>,
15069    ) {
15070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15071
15072        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15073            self.select_syntax_node_history.pop()
15074        {
15075            if let Some(selection) = selections.last_mut() {
15076                selection.reversed = is_selection_reversed;
15077            }
15078
15079            self.select_syntax_node_history.disable_clearing = true;
15080            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15081                s.select(selections.to_vec());
15082            });
15083            self.select_syntax_node_history.disable_clearing = false;
15084
15085            match scroll_behavior {
15086                SelectSyntaxNodeScrollBehavior::CursorTop => {
15087                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15088                }
15089                SelectSyntaxNodeScrollBehavior::FitSelection => {
15090                    self.request_autoscroll(Autoscroll::fit(), cx);
15091                }
15092                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15093                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15094                }
15095            }
15096        }
15097    }
15098
15099    pub fn unwrap_syntax_node(
15100        &mut self,
15101        _: &UnwrapSyntaxNode,
15102        window: &mut Window,
15103        cx: &mut Context<Self>,
15104    ) {
15105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15106
15107        let buffer = self.buffer.read(cx).snapshot(cx);
15108        let selections = self
15109            .selections
15110            .all::<usize>(cx)
15111            .into_iter()
15112            // subtracting the offset requires sorting
15113            .sorted_by_key(|i| i.start);
15114
15115        let full_edits = selections
15116            .into_iter()
15117            .filter_map(|selection| {
15118                // Only requires two branches once if-let-chains stabilize (#53667)
15119                let child = if !selection.is_empty() {
15120                    selection.range()
15121                } else if let Some((_, ancestor_range)) =
15122                    buffer.syntax_ancestor(selection.start..selection.end)
15123                {
15124                    ancestor_range
15125                } else {
15126                    selection.range()
15127                };
15128
15129                let mut parent = child.clone();
15130                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15131                    parent = ancestor_range;
15132                    if parent.start < child.start || parent.end > child.end {
15133                        break;
15134                    }
15135                }
15136
15137                if parent == child {
15138                    return None;
15139                }
15140                let text = buffer.text_for_range(child).collect::<String>();
15141                Some((selection.id, parent, text))
15142            })
15143            .collect::<Vec<_>>();
15144
15145        self.transact(window, cx, |this, window, cx| {
15146            this.buffer.update(cx, |buffer, cx| {
15147                buffer.edit(
15148                    full_edits
15149                        .iter()
15150                        .map(|(_, p, t)| (p.clone(), t.clone()))
15151                        .collect::<Vec<_>>(),
15152                    None,
15153                    cx,
15154                );
15155            });
15156            this.change_selections(Default::default(), window, cx, |s| {
15157                let mut offset = 0;
15158                let mut selections = vec![];
15159                for (id, parent, text) in full_edits {
15160                    let start = parent.start - offset;
15161                    offset += parent.len() - text.len();
15162                    selections.push(Selection {
15163                        id,
15164                        start,
15165                        end: start + text.len(),
15166                        reversed: false,
15167                        goal: Default::default(),
15168                    });
15169                }
15170                s.select(selections);
15171            });
15172        });
15173    }
15174
15175    pub fn select_next_syntax_node(
15176        &mut self,
15177        _: &SelectNextSyntaxNode,
15178        window: &mut Window,
15179        cx: &mut Context<Self>,
15180    ) {
15181        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15182        if old_selections.is_empty() {
15183            return;
15184        }
15185
15186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15187
15188        let buffer = self.buffer.read(cx).snapshot(cx);
15189        let mut selected_sibling = false;
15190
15191        let new_selections = old_selections
15192            .iter()
15193            .map(|selection| {
15194                let old_range = selection.start..selection.end;
15195
15196                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15197                    let new_range = node.byte_range();
15198                    selected_sibling = true;
15199                    Selection {
15200                        id: selection.id,
15201                        start: new_range.start,
15202                        end: new_range.end,
15203                        goal: SelectionGoal::None,
15204                        reversed: selection.reversed,
15205                    }
15206                } else {
15207                    selection.clone()
15208                }
15209            })
15210            .collect::<Vec<_>>();
15211
15212        if selected_sibling {
15213            self.change_selections(
15214                SelectionEffects::scroll(Autoscroll::fit()),
15215                window,
15216                cx,
15217                |s| {
15218                    s.select(new_selections);
15219                },
15220            );
15221        }
15222    }
15223
15224    pub fn select_prev_syntax_node(
15225        &mut self,
15226        _: &SelectPreviousSyntaxNode,
15227        window: &mut Window,
15228        cx: &mut Context<Self>,
15229    ) {
15230        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15231        if old_selections.is_empty() {
15232            return;
15233        }
15234
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236
15237        let buffer = self.buffer.read(cx).snapshot(cx);
15238        let mut selected_sibling = false;
15239
15240        let new_selections = old_selections
15241            .iter()
15242            .map(|selection| {
15243                let old_range = selection.start..selection.end;
15244
15245                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15246                    let new_range = node.byte_range();
15247                    selected_sibling = true;
15248                    Selection {
15249                        id: selection.id,
15250                        start: new_range.start,
15251                        end: new_range.end,
15252                        goal: SelectionGoal::None,
15253                        reversed: selection.reversed,
15254                    }
15255                } else {
15256                    selection.clone()
15257                }
15258            })
15259            .collect::<Vec<_>>();
15260
15261        if selected_sibling {
15262            self.change_selections(
15263                SelectionEffects::scroll(Autoscroll::fit()),
15264                window,
15265                cx,
15266                |s| {
15267                    s.select(new_selections);
15268                },
15269            );
15270        }
15271    }
15272
15273    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15274        if !EditorSettings::get_global(cx).gutter.runnables {
15275            self.clear_tasks();
15276            return Task::ready(());
15277        }
15278        let project = self.project().map(Entity::downgrade);
15279        let task_sources = self.lsp_task_sources(cx);
15280        let multi_buffer = self.buffer.downgrade();
15281        cx.spawn_in(window, async move |editor, cx| {
15282            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15283            let Some(project) = project.and_then(|p| p.upgrade()) else {
15284                return;
15285            };
15286            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15287                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15288            }) else {
15289                return;
15290            };
15291
15292            let hide_runnables = project
15293                .update(cx, |project, _| project.is_via_collab())
15294                .unwrap_or(true);
15295            if hide_runnables {
15296                return;
15297            }
15298            let new_rows =
15299                cx.background_spawn({
15300                    let snapshot = display_snapshot.clone();
15301                    async move {
15302                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15303                    }
15304                })
15305                    .await;
15306            let Ok(lsp_tasks) =
15307                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15308            else {
15309                return;
15310            };
15311            let lsp_tasks = lsp_tasks.await;
15312
15313            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15314                lsp_tasks
15315                    .into_iter()
15316                    .flat_map(|(kind, tasks)| {
15317                        tasks.into_iter().filter_map(move |(location, task)| {
15318                            Some((kind.clone(), location?, task))
15319                        })
15320                    })
15321                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15322                        let buffer = location.target.buffer;
15323                        let buffer_snapshot = buffer.read(cx).snapshot();
15324                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15325                            |(excerpt_id, snapshot, _)| {
15326                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15327                                    display_snapshot
15328                                        .buffer_snapshot
15329                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15330                                } else {
15331                                    None
15332                                }
15333                            },
15334                        );
15335                        if let Some(offset) = offset {
15336                            let task_buffer_range =
15337                                location.target.range.to_point(&buffer_snapshot);
15338                            let context_buffer_range =
15339                                task_buffer_range.to_offset(&buffer_snapshot);
15340                            let context_range = BufferOffset(context_buffer_range.start)
15341                                ..BufferOffset(context_buffer_range.end);
15342
15343                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15344                                .or_insert_with(|| RunnableTasks {
15345                                    templates: Vec::new(),
15346                                    offset,
15347                                    column: task_buffer_range.start.column,
15348                                    extra_variables: HashMap::default(),
15349                                    context_range,
15350                                })
15351                                .templates
15352                                .push((kind, task.original_task().clone()));
15353                        }
15354
15355                        acc
15356                    })
15357            }) else {
15358                return;
15359            };
15360
15361            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15362                buffer.language_settings(cx).tasks.prefer_lsp
15363            }) else {
15364                return;
15365            };
15366
15367            let rows = Self::runnable_rows(
15368                project,
15369                display_snapshot,
15370                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15371                new_rows,
15372                cx.clone(),
15373            )
15374            .await;
15375            editor
15376                .update(cx, |editor, _| {
15377                    editor.clear_tasks();
15378                    for (key, mut value) in rows {
15379                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15380                            value.templates.extend(lsp_tasks.templates);
15381                        }
15382
15383                        editor.insert_tasks(key, value);
15384                    }
15385                    for (key, value) in lsp_tasks_by_rows {
15386                        editor.insert_tasks(key, value);
15387                    }
15388                })
15389                .ok();
15390        })
15391    }
15392    fn fetch_runnable_ranges(
15393        snapshot: &DisplaySnapshot,
15394        range: Range<Anchor>,
15395    ) -> Vec<language::RunnableRange> {
15396        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15397    }
15398
15399    fn runnable_rows(
15400        project: Entity<Project>,
15401        snapshot: DisplaySnapshot,
15402        prefer_lsp: bool,
15403        runnable_ranges: Vec<RunnableRange>,
15404        cx: AsyncWindowContext,
15405    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15406        cx.spawn(async move |cx| {
15407            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15408            for mut runnable in runnable_ranges {
15409                let Some(tasks) = cx
15410                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15411                    .ok()
15412                else {
15413                    continue;
15414                };
15415                let mut tasks = tasks.await;
15416
15417                if prefer_lsp {
15418                    tasks.retain(|(task_kind, _)| {
15419                        !matches!(task_kind, TaskSourceKind::Language { .. })
15420                    });
15421                }
15422                if tasks.is_empty() {
15423                    continue;
15424                }
15425
15426                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15427                let Some(row) = snapshot
15428                    .buffer_snapshot
15429                    .buffer_line_for_row(MultiBufferRow(point.row))
15430                    .map(|(_, range)| range.start.row)
15431                else {
15432                    continue;
15433                };
15434
15435                let context_range =
15436                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15437                runnable_rows.push((
15438                    (runnable.buffer_id, row),
15439                    RunnableTasks {
15440                        templates: tasks,
15441                        offset: snapshot
15442                            .buffer_snapshot
15443                            .anchor_before(runnable.run_range.start),
15444                        context_range,
15445                        column: point.column,
15446                        extra_variables: runnable.extra_captures,
15447                    },
15448                ));
15449            }
15450            runnable_rows
15451        })
15452    }
15453
15454    fn templates_with_tags(
15455        project: &Entity<Project>,
15456        runnable: &mut Runnable,
15457        cx: &mut App,
15458    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15459        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15460            let (worktree_id, file) = project
15461                .buffer_for_id(runnable.buffer, cx)
15462                .and_then(|buffer| buffer.read(cx).file())
15463                .map(|file| (file.worktree_id(cx), file.clone()))
15464                .unzip();
15465
15466            (
15467                project.task_store().read(cx).task_inventory().cloned(),
15468                worktree_id,
15469                file,
15470            )
15471        });
15472
15473        let tags = mem::take(&mut runnable.tags);
15474        let language = runnable.language.clone();
15475        cx.spawn(async move |cx| {
15476            let mut templates_with_tags = Vec::new();
15477            if let Some(inventory) = inventory {
15478                for RunnableTag(tag) in tags {
15479                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15480                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15481                    }) else {
15482                        return templates_with_tags;
15483                    };
15484                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15485                        move |(_, template)| {
15486                            template.tags.iter().any(|source_tag| source_tag == &tag)
15487                        },
15488                    ));
15489                }
15490            }
15491            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15492
15493            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15494                // Strongest source wins; if we have worktree tag binding, prefer that to
15495                // global and language bindings;
15496                // if we have a global binding, prefer that to language binding.
15497                let first_mismatch = templates_with_tags
15498                    .iter()
15499                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15500                if let Some(index) = first_mismatch {
15501                    templates_with_tags.truncate(index);
15502                }
15503            }
15504
15505            templates_with_tags
15506        })
15507    }
15508
15509    pub fn move_to_enclosing_bracket(
15510        &mut self,
15511        _: &MoveToEnclosingBracket,
15512        window: &mut Window,
15513        cx: &mut Context<Self>,
15514    ) {
15515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15516        self.change_selections(Default::default(), window, cx, |s| {
15517            s.move_offsets_with(|snapshot, selection| {
15518                let Some(enclosing_bracket_ranges) =
15519                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15520                else {
15521                    return;
15522                };
15523
15524                let mut best_length = usize::MAX;
15525                let mut best_inside = false;
15526                let mut best_in_bracket_range = false;
15527                let mut best_destination = None;
15528                for (open, close) in enclosing_bracket_ranges {
15529                    let close = close.to_inclusive();
15530                    let length = close.end() - open.start;
15531                    let inside = selection.start >= open.end && selection.end <= *close.start();
15532                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15533                        || close.contains(&selection.head());
15534
15535                    // If best is next to a bracket and current isn't, skip
15536                    if !in_bracket_range && best_in_bracket_range {
15537                        continue;
15538                    }
15539
15540                    // Prefer smaller lengths unless best is inside and current isn't
15541                    if length > best_length && (best_inside || !inside) {
15542                        continue;
15543                    }
15544
15545                    best_length = length;
15546                    best_inside = inside;
15547                    best_in_bracket_range = in_bracket_range;
15548                    best_destination = Some(
15549                        if close.contains(&selection.start) && close.contains(&selection.end) {
15550                            if inside { open.end } else { open.start }
15551                        } else if inside {
15552                            *close.start()
15553                        } else {
15554                            *close.end()
15555                        },
15556                    );
15557                }
15558
15559                if let Some(destination) = best_destination {
15560                    selection.collapse_to(destination, SelectionGoal::None);
15561                }
15562            })
15563        });
15564    }
15565
15566    pub fn undo_selection(
15567        &mut self,
15568        _: &UndoSelection,
15569        window: &mut Window,
15570        cx: &mut Context<Self>,
15571    ) {
15572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15573        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15574            self.selection_history.mode = SelectionHistoryMode::Undoing;
15575            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15576                this.end_selection(window, cx);
15577                this.change_selections(
15578                    SelectionEffects::scroll(Autoscroll::newest()),
15579                    window,
15580                    cx,
15581                    |s| s.select_anchors(entry.selections.to_vec()),
15582                );
15583            });
15584            self.selection_history.mode = SelectionHistoryMode::Normal;
15585
15586            self.select_next_state = entry.select_next_state;
15587            self.select_prev_state = entry.select_prev_state;
15588            self.add_selections_state = entry.add_selections_state;
15589        }
15590    }
15591
15592    pub fn redo_selection(
15593        &mut self,
15594        _: &RedoSelection,
15595        window: &mut Window,
15596        cx: &mut Context<Self>,
15597    ) {
15598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15599        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15600            self.selection_history.mode = SelectionHistoryMode::Redoing;
15601            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15602                this.end_selection(window, cx);
15603                this.change_selections(
15604                    SelectionEffects::scroll(Autoscroll::newest()),
15605                    window,
15606                    cx,
15607                    |s| s.select_anchors(entry.selections.to_vec()),
15608                );
15609            });
15610            self.selection_history.mode = SelectionHistoryMode::Normal;
15611
15612            self.select_next_state = entry.select_next_state;
15613            self.select_prev_state = entry.select_prev_state;
15614            self.add_selections_state = entry.add_selections_state;
15615        }
15616    }
15617
15618    pub fn expand_excerpts(
15619        &mut self,
15620        action: &ExpandExcerpts,
15621        _: &mut Window,
15622        cx: &mut Context<Self>,
15623    ) {
15624        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15625    }
15626
15627    pub fn expand_excerpts_down(
15628        &mut self,
15629        action: &ExpandExcerptsDown,
15630        _: &mut Window,
15631        cx: &mut Context<Self>,
15632    ) {
15633        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15634    }
15635
15636    pub fn expand_excerpts_up(
15637        &mut self,
15638        action: &ExpandExcerptsUp,
15639        _: &mut Window,
15640        cx: &mut Context<Self>,
15641    ) {
15642        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15643    }
15644
15645    pub fn expand_excerpts_for_direction(
15646        &mut self,
15647        lines: u32,
15648        direction: ExpandExcerptDirection,
15649
15650        cx: &mut Context<Self>,
15651    ) {
15652        let selections = self.selections.disjoint_anchors();
15653
15654        let lines = if lines == 0 {
15655            EditorSettings::get_global(cx).expand_excerpt_lines
15656        } else {
15657            lines
15658        };
15659
15660        self.buffer.update(cx, |buffer, cx| {
15661            let snapshot = buffer.snapshot(cx);
15662            let mut excerpt_ids = selections
15663                .iter()
15664                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15665                .collect::<Vec<_>>();
15666            excerpt_ids.sort();
15667            excerpt_ids.dedup();
15668            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15669        })
15670    }
15671
15672    pub fn expand_excerpt(
15673        &mut self,
15674        excerpt: ExcerptId,
15675        direction: ExpandExcerptDirection,
15676        window: &mut Window,
15677        cx: &mut Context<Self>,
15678    ) {
15679        let current_scroll_position = self.scroll_position(cx);
15680        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15681        let mut should_scroll_up = false;
15682
15683        if direction == ExpandExcerptDirection::Down {
15684            let multi_buffer = self.buffer.read(cx);
15685            let snapshot = multi_buffer.snapshot(cx);
15686            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15687                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15688                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15689            {
15690                let buffer_snapshot = buffer.read(cx).snapshot();
15691                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15692                let last_row = buffer_snapshot.max_point().row;
15693                let lines_below = last_row.saturating_sub(excerpt_end_row);
15694                should_scroll_up = lines_below >= lines_to_expand;
15695            }
15696        }
15697
15698        self.buffer.update(cx, |buffer, cx| {
15699            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15700        });
15701
15702        if should_scroll_up {
15703            let new_scroll_position =
15704                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15705            self.set_scroll_position(new_scroll_position, window, cx);
15706        }
15707    }
15708
15709    pub fn go_to_singleton_buffer_point(
15710        &mut self,
15711        point: Point,
15712        window: &mut Window,
15713        cx: &mut Context<Self>,
15714    ) {
15715        self.go_to_singleton_buffer_range(point..point, window, cx);
15716    }
15717
15718    pub fn go_to_singleton_buffer_range(
15719        &mut self,
15720        range: Range<Point>,
15721        window: &mut Window,
15722        cx: &mut Context<Self>,
15723    ) {
15724        let multibuffer = self.buffer().read(cx);
15725        let Some(buffer) = multibuffer.as_singleton() else {
15726            return;
15727        };
15728        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15729            return;
15730        };
15731        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15732            return;
15733        };
15734        self.change_selections(
15735            SelectionEffects::default().nav_history(true),
15736            window,
15737            cx,
15738            |s| s.select_anchor_ranges([start..end]),
15739        );
15740    }
15741
15742    pub fn go_to_diagnostic(
15743        &mut self,
15744        action: &GoToDiagnostic,
15745        window: &mut Window,
15746        cx: &mut Context<Self>,
15747    ) {
15748        if !self.diagnostics_enabled() {
15749            return;
15750        }
15751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15752        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15753    }
15754
15755    pub fn go_to_prev_diagnostic(
15756        &mut self,
15757        action: &GoToPreviousDiagnostic,
15758        window: &mut Window,
15759        cx: &mut Context<Self>,
15760    ) {
15761        if !self.diagnostics_enabled() {
15762            return;
15763        }
15764        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15765        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15766    }
15767
15768    pub fn go_to_diagnostic_impl(
15769        &mut self,
15770        direction: Direction,
15771        severity: GoToDiagnosticSeverityFilter,
15772        window: &mut Window,
15773        cx: &mut Context<Self>,
15774    ) {
15775        let buffer = self.buffer.read(cx).snapshot(cx);
15776        let selection = self.selections.newest::<usize>(cx);
15777
15778        let mut active_group_id = None;
15779        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15780            && active_group.active_range.start.to_offset(&buffer) == selection.start
15781        {
15782            active_group_id = Some(active_group.group_id);
15783        }
15784
15785        fn filtered(
15786            snapshot: EditorSnapshot,
15787            severity: GoToDiagnosticSeverityFilter,
15788            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15789        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15790            diagnostics
15791                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15792                .filter(|entry| entry.range.start != entry.range.end)
15793                .filter(|entry| !entry.diagnostic.is_unnecessary)
15794                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15795        }
15796
15797        let snapshot = self.snapshot(window, cx);
15798        let before = filtered(
15799            snapshot.clone(),
15800            severity,
15801            buffer
15802                .diagnostics_in_range(0..selection.start)
15803                .filter(|entry| entry.range.start <= selection.start),
15804        );
15805        let after = filtered(
15806            snapshot,
15807            severity,
15808            buffer
15809                .diagnostics_in_range(selection.start..buffer.len())
15810                .filter(|entry| entry.range.start >= selection.start),
15811        );
15812
15813        let mut found: Option<DiagnosticEntry<usize>> = None;
15814        if direction == Direction::Prev {
15815            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15816            {
15817                for diagnostic in prev_diagnostics.into_iter().rev() {
15818                    if diagnostic.range.start != selection.start
15819                        || active_group_id
15820                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15821                    {
15822                        found = Some(diagnostic);
15823                        break 'outer;
15824                    }
15825                }
15826            }
15827        } else {
15828            for diagnostic in after.chain(before) {
15829                if diagnostic.range.start != selection.start
15830                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15831                {
15832                    found = Some(diagnostic);
15833                    break;
15834                }
15835            }
15836        }
15837        let Some(next_diagnostic) = found else {
15838            return;
15839        };
15840
15841        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15842        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15843            return;
15844        };
15845        self.change_selections(Default::default(), window, cx, |s| {
15846            s.select_ranges(vec![
15847                next_diagnostic.range.start..next_diagnostic.range.start,
15848            ])
15849        });
15850        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15851        self.refresh_edit_prediction(false, true, window, cx);
15852    }
15853
15854    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15856        let snapshot = self.snapshot(window, cx);
15857        let selection = self.selections.newest::<Point>(cx);
15858        self.go_to_hunk_before_or_after_position(
15859            &snapshot,
15860            selection.head(),
15861            Direction::Next,
15862            window,
15863            cx,
15864        );
15865    }
15866
15867    pub fn go_to_hunk_before_or_after_position(
15868        &mut self,
15869        snapshot: &EditorSnapshot,
15870        position: Point,
15871        direction: Direction,
15872        window: &mut Window,
15873        cx: &mut Context<Editor>,
15874    ) {
15875        let row = if direction == Direction::Next {
15876            self.hunk_after_position(snapshot, position)
15877                .map(|hunk| hunk.row_range.start)
15878        } else {
15879            self.hunk_before_position(snapshot, position)
15880        };
15881
15882        if let Some(row) = row {
15883            let destination = Point::new(row.0, 0);
15884            let autoscroll = Autoscroll::center();
15885
15886            self.unfold_ranges(&[destination..destination], false, false, cx);
15887            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15888                s.select_ranges([destination..destination]);
15889            });
15890        }
15891    }
15892
15893    fn hunk_after_position(
15894        &mut self,
15895        snapshot: &EditorSnapshot,
15896        position: Point,
15897    ) -> Option<MultiBufferDiffHunk> {
15898        snapshot
15899            .buffer_snapshot
15900            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15901            .find(|hunk| hunk.row_range.start.0 > position.row)
15902            .or_else(|| {
15903                snapshot
15904                    .buffer_snapshot
15905                    .diff_hunks_in_range(Point::zero()..position)
15906                    .find(|hunk| hunk.row_range.end.0 < position.row)
15907            })
15908    }
15909
15910    fn go_to_prev_hunk(
15911        &mut self,
15912        _: &GoToPreviousHunk,
15913        window: &mut Window,
15914        cx: &mut Context<Self>,
15915    ) {
15916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15917        let snapshot = self.snapshot(window, cx);
15918        let selection = self.selections.newest::<Point>(cx);
15919        self.go_to_hunk_before_or_after_position(
15920            &snapshot,
15921            selection.head(),
15922            Direction::Prev,
15923            window,
15924            cx,
15925        );
15926    }
15927
15928    fn hunk_before_position(
15929        &mut self,
15930        snapshot: &EditorSnapshot,
15931        position: Point,
15932    ) -> Option<MultiBufferRow> {
15933        snapshot
15934            .buffer_snapshot
15935            .diff_hunk_before(position)
15936            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15937    }
15938
15939    fn go_to_next_change(
15940        &mut self,
15941        _: &GoToNextChange,
15942        window: &mut Window,
15943        cx: &mut Context<Self>,
15944    ) {
15945        if let Some(selections) = self
15946            .change_list
15947            .next_change(1, Direction::Next)
15948            .map(|s| s.to_vec())
15949        {
15950            self.change_selections(Default::default(), window, cx, |s| {
15951                let map = s.display_map();
15952                s.select_display_ranges(selections.iter().map(|a| {
15953                    let point = a.to_display_point(&map);
15954                    point..point
15955                }))
15956            })
15957        }
15958    }
15959
15960    fn go_to_previous_change(
15961        &mut self,
15962        _: &GoToPreviousChange,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) {
15966        if let Some(selections) = self
15967            .change_list
15968            .next_change(1, Direction::Prev)
15969            .map(|s| s.to_vec())
15970        {
15971            self.change_selections(Default::default(), window, cx, |s| {
15972                let map = s.display_map();
15973                s.select_display_ranges(selections.iter().map(|a| {
15974                    let point = a.to_display_point(&map);
15975                    point..point
15976                }))
15977            })
15978        }
15979    }
15980
15981    pub fn go_to_next_document_highlight(
15982        &mut self,
15983        _: &GoToNextDocumentHighlight,
15984        window: &mut Window,
15985        cx: &mut Context<Self>,
15986    ) {
15987        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
15988    }
15989
15990    pub fn go_to_prev_document_highlight(
15991        &mut self,
15992        _: &GoToPreviousDocumentHighlight,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
15997    }
15998
15999    pub fn go_to_document_highlight_before_or_after_position(
16000        &mut self,
16001        direction: Direction,
16002        window: &mut Window,
16003        cx: &mut Context<Editor>,
16004    ) {
16005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16006        let snapshot = self.snapshot(window, cx);
16007        let buffer = &snapshot.buffer_snapshot;
16008        let position = self.selections.newest::<Point>(cx).head();
16009        let anchor_position = buffer.anchor_after(position);
16010
16011        // Get all document highlights (both read and write)
16012        let mut all_highlights = Vec::new();
16013
16014        if let Some((_, read_highlights)) = self
16015            .background_highlights
16016            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16017        {
16018            all_highlights.extend(read_highlights.iter());
16019        }
16020
16021        if let Some((_, write_highlights)) = self
16022            .background_highlights
16023            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16024        {
16025            all_highlights.extend(write_highlights.iter());
16026        }
16027
16028        if all_highlights.is_empty() {
16029            return;
16030        }
16031
16032        // Sort highlights by position
16033        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16034
16035        let target_highlight = match direction {
16036            Direction::Next => {
16037                // Find the first highlight after the current position
16038                all_highlights
16039                    .iter()
16040                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16041            }
16042            Direction::Prev => {
16043                // Find the last highlight before the current position
16044                all_highlights
16045                    .iter()
16046                    .rev()
16047                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16048            }
16049        };
16050
16051        if let Some(highlight) = target_highlight {
16052            let destination = highlight.start.to_point(buffer);
16053            let autoscroll = Autoscroll::center();
16054
16055            self.unfold_ranges(&[destination..destination], false, false, cx);
16056            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16057                s.select_ranges([destination..destination]);
16058            });
16059        }
16060    }
16061
16062    fn go_to_line<T: 'static>(
16063        &mut self,
16064        position: Anchor,
16065        highlight_color: Option<Hsla>,
16066        window: &mut Window,
16067        cx: &mut Context<Self>,
16068    ) {
16069        let snapshot = self.snapshot(window, cx).display_snapshot;
16070        let position = position.to_point(&snapshot.buffer_snapshot);
16071        let start = snapshot
16072            .buffer_snapshot
16073            .clip_point(Point::new(position.row, 0), Bias::Left);
16074        let end = start + Point::new(1, 0);
16075        let start = snapshot.buffer_snapshot.anchor_before(start);
16076        let end = snapshot.buffer_snapshot.anchor_before(end);
16077
16078        self.highlight_rows::<T>(
16079            start..end,
16080            highlight_color
16081                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16082            Default::default(),
16083            cx,
16084        );
16085
16086        if self.buffer.read(cx).is_singleton() {
16087            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16088        }
16089    }
16090
16091    pub fn go_to_definition(
16092        &mut self,
16093        _: &GoToDefinition,
16094        window: &mut Window,
16095        cx: &mut Context<Self>,
16096    ) -> Task<Result<Navigated>> {
16097        let definition =
16098            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16099        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16100        cx.spawn_in(window, async move |editor, cx| {
16101            if definition.await? == Navigated::Yes {
16102                return Ok(Navigated::Yes);
16103            }
16104            match fallback_strategy {
16105                GoToDefinitionFallback::None => Ok(Navigated::No),
16106                GoToDefinitionFallback::FindAllReferences => {
16107                    match editor.update_in(cx, |editor, window, cx| {
16108                        editor.find_all_references(&FindAllReferences, window, cx)
16109                    })? {
16110                        Some(references) => references.await,
16111                        None => Ok(Navigated::No),
16112                    }
16113                }
16114            }
16115        })
16116    }
16117
16118    pub fn go_to_declaration(
16119        &mut self,
16120        _: &GoToDeclaration,
16121        window: &mut Window,
16122        cx: &mut Context<Self>,
16123    ) -> Task<Result<Navigated>> {
16124        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16125    }
16126
16127    pub fn go_to_declaration_split(
16128        &mut self,
16129        _: &GoToDeclaration,
16130        window: &mut Window,
16131        cx: &mut Context<Self>,
16132    ) -> Task<Result<Navigated>> {
16133        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16134    }
16135
16136    pub fn go_to_implementation(
16137        &mut self,
16138        _: &GoToImplementation,
16139        window: &mut Window,
16140        cx: &mut Context<Self>,
16141    ) -> Task<Result<Navigated>> {
16142        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16143    }
16144
16145    pub fn go_to_implementation_split(
16146        &mut self,
16147        _: &GoToImplementationSplit,
16148        window: &mut Window,
16149        cx: &mut Context<Self>,
16150    ) -> Task<Result<Navigated>> {
16151        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16152    }
16153
16154    pub fn go_to_type_definition(
16155        &mut self,
16156        _: &GoToTypeDefinition,
16157        window: &mut Window,
16158        cx: &mut Context<Self>,
16159    ) -> Task<Result<Navigated>> {
16160        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16161    }
16162
16163    pub fn go_to_definition_split(
16164        &mut self,
16165        _: &GoToDefinitionSplit,
16166        window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) -> Task<Result<Navigated>> {
16169        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16170    }
16171
16172    pub fn go_to_type_definition_split(
16173        &mut self,
16174        _: &GoToTypeDefinitionSplit,
16175        window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) -> Task<Result<Navigated>> {
16178        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16179    }
16180
16181    fn go_to_definition_of_kind(
16182        &mut self,
16183        kind: GotoDefinitionKind,
16184        split: bool,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) -> Task<Result<Navigated>> {
16188        let Some(provider) = self.semantics_provider.clone() else {
16189            return Task::ready(Ok(Navigated::No));
16190        };
16191        let head = self.selections.newest::<usize>(cx).head();
16192        let buffer = self.buffer.read(cx);
16193        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16194            return Task::ready(Ok(Navigated::No));
16195        };
16196        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16197            return Task::ready(Ok(Navigated::No));
16198        };
16199
16200        cx.spawn_in(window, async move |editor, cx| {
16201            let Some(definitions) = definitions.await? else {
16202                return Ok(Navigated::No);
16203            };
16204            let navigated = editor
16205                .update_in(cx, |editor, window, cx| {
16206                    editor.navigate_to_hover_links(
16207                        Some(kind),
16208                        definitions
16209                            .into_iter()
16210                            .filter(|location| {
16211                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16212                            })
16213                            .map(HoverLink::Text)
16214                            .collect::<Vec<_>>(),
16215                        split,
16216                        window,
16217                        cx,
16218                    )
16219                })?
16220                .await?;
16221            anyhow::Ok(navigated)
16222        })
16223    }
16224
16225    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16226        let selection = self.selections.newest_anchor();
16227        let head = selection.head();
16228        let tail = selection.tail();
16229
16230        let Some((buffer, start_position)) =
16231            self.buffer.read(cx).text_anchor_for_position(head, cx)
16232        else {
16233            return;
16234        };
16235
16236        let end_position = if head != tail {
16237            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16238                return;
16239            };
16240            Some(pos)
16241        } else {
16242            None
16243        };
16244
16245        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16246            let url = if let Some(end_pos) = end_position {
16247                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16248            } else {
16249                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16250            };
16251
16252            if let Some(url) = url {
16253                editor.update(cx, |_, cx| {
16254                    cx.open_url(&url);
16255                })
16256            } else {
16257                Ok(())
16258            }
16259        });
16260
16261        url_finder.detach();
16262    }
16263
16264    pub fn open_selected_filename(
16265        &mut self,
16266        _: &OpenSelectedFilename,
16267        window: &mut Window,
16268        cx: &mut Context<Self>,
16269    ) {
16270        let Some(workspace) = self.workspace() else {
16271            return;
16272        };
16273
16274        let position = self.selections.newest_anchor().head();
16275
16276        let Some((buffer, buffer_position)) =
16277            self.buffer.read(cx).text_anchor_for_position(position, cx)
16278        else {
16279            return;
16280        };
16281
16282        let project = self.project.clone();
16283
16284        cx.spawn_in(window, async move |_, cx| {
16285            let result = find_file(&buffer, project, buffer_position, cx).await;
16286
16287            if let Some((_, path)) = result {
16288                workspace
16289                    .update_in(cx, |workspace, window, cx| {
16290                        workspace.open_resolved_path(path, window, cx)
16291                    })?
16292                    .await?;
16293            }
16294            anyhow::Ok(())
16295        })
16296        .detach();
16297    }
16298
16299    pub(crate) fn navigate_to_hover_links(
16300        &mut self,
16301        kind: Option<GotoDefinitionKind>,
16302        definitions: Vec<HoverLink>,
16303        split: bool,
16304        window: &mut Window,
16305        cx: &mut Context<Editor>,
16306    ) -> Task<Result<Navigated>> {
16307        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16308        let mut first_url_or_file = None;
16309        let definitions: Vec<_> = definitions
16310            .into_iter()
16311            .filter_map(|def| match def {
16312                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16313                HoverLink::InlayHint(lsp_location, server_id) => {
16314                    let computation =
16315                        self.compute_target_location(lsp_location, server_id, window, cx);
16316                    Some(cx.background_spawn(computation))
16317                }
16318                HoverLink::Url(url) => {
16319                    first_url_or_file = Some(Either::Left(url));
16320                    None
16321                }
16322                HoverLink::File(path) => {
16323                    first_url_or_file = Some(Either::Right(path));
16324                    None
16325                }
16326            })
16327            .collect();
16328
16329        let workspace = self.workspace();
16330
16331        cx.spawn_in(window, async move |editor, acx| {
16332            let mut locations: Vec<Location> = future::join_all(definitions)
16333                .await
16334                .into_iter()
16335                .filter_map(|location| location.transpose())
16336                .collect::<Result<_>>()
16337                .context("location tasks")?;
16338
16339            if locations.len() > 1 {
16340                let Some(workspace) = workspace else {
16341                    return Ok(Navigated::No);
16342                };
16343
16344                let tab_kind = match kind {
16345                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16346                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16347                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16348                    Some(GotoDefinitionKind::Type) => "Types",
16349                };
16350                let title = editor
16351                    .update_in(acx, |_, _, cx| {
16352                        let target = locations
16353                            .iter()
16354                            .map(|location| {
16355                                location
16356                                    .buffer
16357                                    .read(cx)
16358                                    .text_for_range(location.range.clone())
16359                                    .collect::<String>()
16360                            })
16361                            .filter(|text| !text.contains('\n'))
16362                            .unique()
16363                            .take(3)
16364                            .join(", ");
16365                        if target.is_empty() {
16366                            tab_kind.to_owned()
16367                        } else {
16368                            format!("{tab_kind} for {target}")
16369                        }
16370                    })
16371                    .context("buffer title")?;
16372
16373                let opened = workspace
16374                    .update_in(acx, |workspace, window, cx| {
16375                        Self::open_locations_in_multibuffer(
16376                            workspace,
16377                            locations,
16378                            title,
16379                            split,
16380                            MultibufferSelectionMode::First,
16381                            window,
16382                            cx,
16383                        )
16384                    })
16385                    .is_ok();
16386
16387                anyhow::Ok(Navigated::from_bool(opened))
16388            } else if locations.is_empty() {
16389                // If there is one url or file, open it directly
16390                match first_url_or_file {
16391                    Some(Either::Left(url)) => {
16392                        acx.update(|_, cx| cx.open_url(&url))?;
16393                        Ok(Navigated::Yes)
16394                    }
16395                    Some(Either::Right(path)) => {
16396                        let Some(workspace) = workspace else {
16397                            return Ok(Navigated::No);
16398                        };
16399
16400                        workspace
16401                            .update_in(acx, |workspace, window, cx| {
16402                                workspace.open_resolved_path(path, window, cx)
16403                            })?
16404                            .await?;
16405                        Ok(Navigated::Yes)
16406                    }
16407                    None => Ok(Navigated::No),
16408                }
16409            } else {
16410                let Some(workspace) = workspace else {
16411                    return Ok(Navigated::No);
16412                };
16413
16414                let target = locations.pop().unwrap();
16415                editor.update_in(acx, |editor, window, cx| {
16416                    let range = target.range.to_point(target.buffer.read(cx));
16417                    let range = editor.range_for_match(&range);
16418                    let range = collapse_multiline_range(range);
16419
16420                    if !split
16421                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16422                    {
16423                        editor.go_to_singleton_buffer_range(range, window, cx);
16424                    } else {
16425                        let pane = workspace.read(cx).active_pane().clone();
16426                        window.defer(cx, move |window, cx| {
16427                            let target_editor: Entity<Self> =
16428                                workspace.update(cx, |workspace, cx| {
16429                                    let pane = if split {
16430                                        workspace.adjacent_pane(window, cx)
16431                                    } else {
16432                                        workspace.active_pane().clone()
16433                                    };
16434
16435                                    workspace.open_project_item(
16436                                        pane,
16437                                        target.buffer.clone(),
16438                                        true,
16439                                        true,
16440                                        window,
16441                                        cx,
16442                                    )
16443                                });
16444                            target_editor.update(cx, |target_editor, cx| {
16445                                // When selecting a definition in a different buffer, disable the nav history
16446                                // to avoid creating a history entry at the previous cursor location.
16447                                pane.update(cx, |pane, _| pane.disable_history());
16448                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16449                                pane.update(cx, |pane, _| pane.enable_history());
16450                            });
16451                        });
16452                    }
16453                    Navigated::Yes
16454                })
16455            }
16456        })
16457    }
16458
16459    fn compute_target_location(
16460        &self,
16461        lsp_location: lsp::Location,
16462        server_id: LanguageServerId,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) -> Task<anyhow::Result<Option<Location>>> {
16466        let Some(project) = self.project.clone() else {
16467            return Task::ready(Ok(None));
16468        };
16469
16470        cx.spawn_in(window, async move |editor, cx| {
16471            let location_task = editor.update(cx, |_, cx| {
16472                project.update(cx, |project, cx| {
16473                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16474                })
16475            })?;
16476            let location = Some({
16477                let target_buffer_handle = location_task.await.context("open local buffer")?;
16478                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16479                    let target_start = target_buffer
16480                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16481                    let target_end = target_buffer
16482                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16483                    target_buffer.anchor_after(target_start)
16484                        ..target_buffer.anchor_before(target_end)
16485                })?;
16486                Location {
16487                    buffer: target_buffer_handle,
16488                    range,
16489                }
16490            });
16491            Ok(location)
16492        })
16493    }
16494
16495    pub fn find_all_references(
16496        &mut self,
16497        _: &FindAllReferences,
16498        window: &mut Window,
16499        cx: &mut Context<Self>,
16500    ) -> Option<Task<Result<Navigated>>> {
16501        let selection = self.selections.newest::<usize>(cx);
16502        let multi_buffer = self.buffer.read(cx);
16503        let head = selection.head();
16504
16505        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16506        let head_anchor = multi_buffer_snapshot.anchor_at(
16507            head,
16508            if head < selection.tail() {
16509                Bias::Right
16510            } else {
16511                Bias::Left
16512            },
16513        );
16514
16515        match self
16516            .find_all_references_task_sources
16517            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16518        {
16519            Ok(_) => {
16520                log::info!(
16521                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16522                );
16523                return None;
16524            }
16525            Err(i) => {
16526                self.find_all_references_task_sources.insert(i, head_anchor);
16527            }
16528        }
16529
16530        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16531        let workspace = self.workspace()?;
16532        let project = workspace.read(cx).project().clone();
16533        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16534        Some(cx.spawn_in(window, async move |editor, cx| {
16535            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16536                if let Ok(i) = editor
16537                    .find_all_references_task_sources
16538                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16539                {
16540                    editor.find_all_references_task_sources.remove(i);
16541                }
16542            });
16543
16544            let Some(locations) = references.await? else {
16545                return anyhow::Ok(Navigated::No);
16546            };
16547            if locations.is_empty() {
16548                return anyhow::Ok(Navigated::No);
16549            }
16550
16551            workspace.update_in(cx, |workspace, window, cx| {
16552                let target = locations
16553                    .iter()
16554                    .map(|location| {
16555                        location
16556                            .buffer
16557                            .read(cx)
16558                            .text_for_range(location.range.clone())
16559                            .collect::<String>()
16560                    })
16561                    .filter(|text| !text.contains('\n'))
16562                    .unique()
16563                    .take(3)
16564                    .join(", ");
16565                let title = if target.is_empty() {
16566                    "References".to_owned()
16567                } else {
16568                    format!("References to {target}")
16569                };
16570                Self::open_locations_in_multibuffer(
16571                    workspace,
16572                    locations,
16573                    title,
16574                    false,
16575                    MultibufferSelectionMode::First,
16576                    window,
16577                    cx,
16578                );
16579                Navigated::Yes
16580            })
16581        }))
16582    }
16583
16584    /// Opens a multibuffer with the given project locations in it
16585    pub fn open_locations_in_multibuffer(
16586        workspace: &mut Workspace,
16587        mut locations: Vec<Location>,
16588        title: String,
16589        split: bool,
16590        multibuffer_selection_mode: MultibufferSelectionMode,
16591        window: &mut Window,
16592        cx: &mut Context<Workspace>,
16593    ) {
16594        if locations.is_empty() {
16595            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16596            return;
16597        }
16598
16599        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16600
16601        let mut locations = locations.into_iter().peekable();
16602        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16603        let capability = workspace.project().read(cx).capability();
16604
16605        // a key to find existing multibuffer editors with the same set of locations
16606        // to prevent us from opening more and more multibuffer tabs for searches and the like
16607        let mut key = (title.clone(), vec![]);
16608        let excerpt_buffer = cx.new(|cx| {
16609            let key = &mut key.1;
16610            let mut multibuffer = MultiBuffer::new(capability);
16611            while let Some(location) = locations.next() {
16612                let buffer = location.buffer.read(cx);
16613                let mut ranges_for_buffer = Vec::new();
16614                let range = location.range.to_point(buffer);
16615                ranges_for_buffer.push(range.clone());
16616
16617                while let Some(next_location) =
16618                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16619                {
16620                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16621                }
16622
16623                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16624                key.push((
16625                    location.buffer.read(cx).remote_id(),
16626                    ranges_for_buffer.clone(),
16627                ));
16628                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16629                    PathKey::for_buffer(&location.buffer, cx),
16630                    location.buffer.clone(),
16631                    ranges_for_buffer,
16632                    multibuffer_context_lines(cx),
16633                    cx,
16634                );
16635                ranges.extend(new_ranges)
16636            }
16637
16638            multibuffer.with_title(title)
16639        });
16640        let existing = workspace.active_pane().update(cx, |pane, cx| {
16641            pane.items()
16642                .filter_map(|item| item.downcast::<Editor>())
16643                .find(|editor| {
16644                    editor
16645                        .read(cx)
16646                        .lookup_key
16647                        .as_ref()
16648                        .and_then(|it| {
16649                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16650                        })
16651                        .is_some_and(|it| *it == key)
16652                })
16653        });
16654        let editor = existing.unwrap_or_else(|| {
16655            cx.new(|cx| {
16656                let mut editor = Editor::for_multibuffer(
16657                    excerpt_buffer,
16658                    Some(workspace.project().clone()),
16659                    window,
16660                    cx,
16661                );
16662                editor.lookup_key = Some(Box::new(key));
16663                editor
16664            })
16665        });
16666        editor.update(cx, |editor, cx| {
16667            match multibuffer_selection_mode {
16668                MultibufferSelectionMode::First => {
16669                    if let Some(first_range) = ranges.first() {
16670                        editor.change_selections(
16671                            SelectionEffects::no_scroll(),
16672                            window,
16673                            cx,
16674                            |selections| {
16675                                selections.clear_disjoint();
16676                                selections
16677                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16678                            },
16679                        );
16680                    }
16681                    editor.highlight_background::<Self>(
16682                        &ranges,
16683                        |theme| theme.colors().editor_highlighted_line_background,
16684                        cx,
16685                    );
16686                }
16687                MultibufferSelectionMode::All => {
16688                    editor.change_selections(
16689                        SelectionEffects::no_scroll(),
16690                        window,
16691                        cx,
16692                        |selections| {
16693                            selections.clear_disjoint();
16694                            selections.select_anchor_ranges(ranges);
16695                        },
16696                    );
16697                }
16698            }
16699            editor.register_buffers_with_language_servers(cx);
16700        });
16701
16702        let item = Box::new(editor);
16703        let item_id = item.item_id();
16704
16705        if split {
16706            workspace.split_item(SplitDirection::Right, item, window, cx);
16707        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16708            let (preview_item_id, preview_item_idx) =
16709                workspace.active_pane().read_with(cx, |pane, _| {
16710                    (pane.preview_item_id(), pane.preview_item_idx())
16711                });
16712
16713            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16714
16715            if let Some(preview_item_id) = preview_item_id {
16716                workspace.active_pane().update(cx, |pane, cx| {
16717                    pane.remove_item(preview_item_id, false, false, window, cx);
16718                });
16719            }
16720        } else {
16721            workspace.add_item_to_active_pane(item, None, true, window, cx);
16722        }
16723        workspace.active_pane().update(cx, |pane, cx| {
16724            pane.set_preview_item_id(Some(item_id), cx);
16725        });
16726    }
16727
16728    pub fn rename(
16729        &mut self,
16730        _: &Rename,
16731        window: &mut Window,
16732        cx: &mut Context<Self>,
16733    ) -> Option<Task<Result<()>>> {
16734        use language::ToOffset as _;
16735
16736        let provider = self.semantics_provider.clone()?;
16737        let selection = self.selections.newest_anchor().clone();
16738        let (cursor_buffer, cursor_buffer_position) = self
16739            .buffer
16740            .read(cx)
16741            .text_anchor_for_position(selection.head(), cx)?;
16742        let (tail_buffer, cursor_buffer_position_end) = self
16743            .buffer
16744            .read(cx)
16745            .text_anchor_for_position(selection.tail(), cx)?;
16746        if tail_buffer != cursor_buffer {
16747            return None;
16748        }
16749
16750        let snapshot = cursor_buffer.read(cx).snapshot();
16751        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16752        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16753        let prepare_rename = provider
16754            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16755            .unwrap_or_else(|| Task::ready(Ok(None)));
16756        drop(snapshot);
16757
16758        Some(cx.spawn_in(window, async move |this, cx| {
16759            let rename_range = if let Some(range) = prepare_rename.await? {
16760                Some(range)
16761            } else {
16762                this.update(cx, |this, cx| {
16763                    let buffer = this.buffer.read(cx).snapshot(cx);
16764                    let mut buffer_highlights = this
16765                        .document_highlights_for_position(selection.head(), &buffer)
16766                        .filter(|highlight| {
16767                            highlight.start.excerpt_id == selection.head().excerpt_id
16768                                && highlight.end.excerpt_id == selection.head().excerpt_id
16769                        });
16770                    buffer_highlights
16771                        .next()
16772                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16773                })?
16774            };
16775            if let Some(rename_range) = rename_range {
16776                this.update_in(cx, |this, window, cx| {
16777                    let snapshot = cursor_buffer.read(cx).snapshot();
16778                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16779                    let cursor_offset_in_rename_range =
16780                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16781                    let cursor_offset_in_rename_range_end =
16782                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16783
16784                    this.take_rename(false, window, cx);
16785                    let buffer = this.buffer.read(cx).read(cx);
16786                    let cursor_offset = selection.head().to_offset(&buffer);
16787                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16788                    let rename_end = rename_start + rename_buffer_range.len();
16789                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16790                    let mut old_highlight_id = None;
16791                    let old_name: Arc<str> = buffer
16792                        .chunks(rename_start..rename_end, true)
16793                        .map(|chunk| {
16794                            if old_highlight_id.is_none() {
16795                                old_highlight_id = chunk.syntax_highlight_id;
16796                            }
16797                            chunk.text
16798                        })
16799                        .collect::<String>()
16800                        .into();
16801
16802                    drop(buffer);
16803
16804                    // Position the selection in the rename editor so that it matches the current selection.
16805                    this.show_local_selections = false;
16806                    let rename_editor = cx.new(|cx| {
16807                        let mut editor = Editor::single_line(window, cx);
16808                        editor.buffer.update(cx, |buffer, cx| {
16809                            buffer.edit([(0..0, old_name.clone())], None, cx)
16810                        });
16811                        let rename_selection_range = match cursor_offset_in_rename_range
16812                            .cmp(&cursor_offset_in_rename_range_end)
16813                        {
16814                            Ordering::Equal => {
16815                                editor.select_all(&SelectAll, window, cx);
16816                                return editor;
16817                            }
16818                            Ordering::Less => {
16819                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16820                            }
16821                            Ordering::Greater => {
16822                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16823                            }
16824                        };
16825                        if rename_selection_range.end > old_name.len() {
16826                            editor.select_all(&SelectAll, window, cx);
16827                        } else {
16828                            editor.change_selections(Default::default(), window, cx, |s| {
16829                                s.select_ranges([rename_selection_range]);
16830                            });
16831                        }
16832                        editor
16833                    });
16834                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16835                        if e == &EditorEvent::Focused {
16836                            cx.emit(EditorEvent::FocusedIn)
16837                        }
16838                    })
16839                    .detach();
16840
16841                    let write_highlights =
16842                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16843                    let read_highlights =
16844                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16845                    let ranges = write_highlights
16846                        .iter()
16847                        .flat_map(|(_, ranges)| ranges.iter())
16848                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16849                        .cloned()
16850                        .collect();
16851
16852                    this.highlight_text::<Rename>(
16853                        ranges,
16854                        HighlightStyle {
16855                            fade_out: Some(0.6),
16856                            ..Default::default()
16857                        },
16858                        cx,
16859                    );
16860                    let rename_focus_handle = rename_editor.focus_handle(cx);
16861                    window.focus(&rename_focus_handle);
16862                    let block_id = this.insert_blocks(
16863                        [BlockProperties {
16864                            style: BlockStyle::Flex,
16865                            placement: BlockPlacement::Below(range.start),
16866                            height: Some(1),
16867                            render: Arc::new({
16868                                let rename_editor = rename_editor.clone();
16869                                move |cx: &mut BlockContext| {
16870                                    let mut text_style = cx.editor_style.text.clone();
16871                                    if let Some(highlight_style) = old_highlight_id
16872                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16873                                    {
16874                                        text_style = text_style.highlight(highlight_style);
16875                                    }
16876                                    div()
16877                                        .block_mouse_except_scroll()
16878                                        .pl(cx.anchor_x)
16879                                        .child(EditorElement::new(
16880                                            &rename_editor,
16881                                            EditorStyle {
16882                                                background: cx.theme().system().transparent,
16883                                                local_player: cx.editor_style.local_player,
16884                                                text: text_style,
16885                                                scrollbar_width: cx.editor_style.scrollbar_width,
16886                                                syntax: cx.editor_style.syntax.clone(),
16887                                                status: cx.editor_style.status.clone(),
16888                                                inlay_hints_style: HighlightStyle {
16889                                                    font_weight: Some(FontWeight::BOLD),
16890                                                    ..make_inlay_hints_style(cx.app)
16891                                                },
16892                                                edit_prediction_styles: make_suggestion_styles(
16893                                                    cx.app,
16894                                                ),
16895                                                ..EditorStyle::default()
16896                                            },
16897                                        ))
16898                                        .into_any_element()
16899                                }
16900                            }),
16901                            priority: 0,
16902                        }],
16903                        Some(Autoscroll::fit()),
16904                        cx,
16905                    )[0];
16906                    this.pending_rename = Some(RenameState {
16907                        range,
16908                        old_name,
16909                        editor: rename_editor,
16910                        block_id,
16911                    });
16912                })?;
16913            }
16914
16915            Ok(())
16916        }))
16917    }
16918
16919    pub fn confirm_rename(
16920        &mut self,
16921        _: &ConfirmRename,
16922        window: &mut Window,
16923        cx: &mut Context<Self>,
16924    ) -> Option<Task<Result<()>>> {
16925        let rename = self.take_rename(false, window, cx)?;
16926        let workspace = self.workspace()?.downgrade();
16927        let (buffer, start) = self
16928            .buffer
16929            .read(cx)
16930            .text_anchor_for_position(rename.range.start, cx)?;
16931        let (end_buffer, _) = self
16932            .buffer
16933            .read(cx)
16934            .text_anchor_for_position(rename.range.end, cx)?;
16935        if buffer != end_buffer {
16936            return None;
16937        }
16938
16939        let old_name = rename.old_name;
16940        let new_name = rename.editor.read(cx).text(cx);
16941
16942        let rename = self.semantics_provider.as_ref()?.perform_rename(
16943            &buffer,
16944            start,
16945            new_name.clone(),
16946            cx,
16947        )?;
16948
16949        Some(cx.spawn_in(window, async move |editor, cx| {
16950            let project_transaction = rename.await?;
16951            Self::open_project_transaction(
16952                &editor,
16953                workspace,
16954                project_transaction,
16955                format!("Rename: {}{}", old_name, new_name),
16956                cx,
16957            )
16958            .await?;
16959
16960            editor.update(cx, |editor, cx| {
16961                editor.refresh_document_highlights(cx);
16962            })?;
16963            Ok(())
16964        }))
16965    }
16966
16967    fn take_rename(
16968        &mut self,
16969        moving_cursor: bool,
16970        window: &mut Window,
16971        cx: &mut Context<Self>,
16972    ) -> Option<RenameState> {
16973        let rename = self.pending_rename.take()?;
16974        if rename.editor.focus_handle(cx).is_focused(window) {
16975            window.focus(&self.focus_handle);
16976        }
16977
16978        self.remove_blocks(
16979            [rename.block_id].into_iter().collect(),
16980            Some(Autoscroll::fit()),
16981            cx,
16982        );
16983        self.clear_highlights::<Rename>(cx);
16984        self.show_local_selections = true;
16985
16986        if moving_cursor {
16987            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16988                editor.selections.newest::<usize>(cx).head()
16989            });
16990
16991            // Update the selection to match the position of the selection inside
16992            // the rename editor.
16993            let snapshot = self.buffer.read(cx).read(cx);
16994            let rename_range = rename.range.to_offset(&snapshot);
16995            let cursor_in_editor = snapshot
16996                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16997                .min(rename_range.end);
16998            drop(snapshot);
16999
17000            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17001                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17002            });
17003        } else {
17004            self.refresh_document_highlights(cx);
17005        }
17006
17007        Some(rename)
17008    }
17009
17010    pub fn pending_rename(&self) -> Option<&RenameState> {
17011        self.pending_rename.as_ref()
17012    }
17013
17014    fn format(
17015        &mut self,
17016        _: &Format,
17017        window: &mut Window,
17018        cx: &mut Context<Self>,
17019    ) -> Option<Task<Result<()>>> {
17020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17021
17022        let project = match &self.project {
17023            Some(project) => project.clone(),
17024            None => return None,
17025        };
17026
17027        Some(self.perform_format(
17028            project,
17029            FormatTrigger::Manual,
17030            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17031            window,
17032            cx,
17033        ))
17034    }
17035
17036    fn format_selections(
17037        &mut self,
17038        _: &FormatSelections,
17039        window: &mut Window,
17040        cx: &mut Context<Self>,
17041    ) -> Option<Task<Result<()>>> {
17042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17043
17044        let project = match &self.project {
17045            Some(project) => project.clone(),
17046            None => return None,
17047        };
17048
17049        let ranges = self
17050            .selections
17051            .all_adjusted(cx)
17052            .into_iter()
17053            .map(|selection| selection.range())
17054            .collect_vec();
17055
17056        Some(self.perform_format(
17057            project,
17058            FormatTrigger::Manual,
17059            FormatTarget::Ranges(ranges),
17060            window,
17061            cx,
17062        ))
17063    }
17064
17065    fn perform_format(
17066        &mut self,
17067        project: Entity<Project>,
17068        trigger: FormatTrigger,
17069        target: FormatTarget,
17070        window: &mut Window,
17071        cx: &mut Context<Self>,
17072    ) -> Task<Result<()>> {
17073        let buffer = self.buffer.clone();
17074        let (buffers, target) = match target {
17075            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17076            FormatTarget::Ranges(selection_ranges) => {
17077                let multi_buffer = buffer.read(cx);
17078                let snapshot = multi_buffer.read(cx);
17079                let mut buffers = HashSet::default();
17080                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17081                    BTreeMap::new();
17082                for selection_range in selection_ranges {
17083                    for (buffer, buffer_range, _) in
17084                        snapshot.range_to_buffer_ranges(selection_range)
17085                    {
17086                        let buffer_id = buffer.remote_id();
17087                        let start = buffer.anchor_before(buffer_range.start);
17088                        let end = buffer.anchor_after(buffer_range.end);
17089                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17090                        buffer_id_to_ranges
17091                            .entry(buffer_id)
17092                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17093                            .or_insert_with(|| vec![start..end]);
17094                    }
17095                }
17096                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17097            }
17098        };
17099
17100        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17101        let selections_prev = transaction_id_prev
17102            .and_then(|transaction_id_prev| {
17103                // default to selections as they were after the last edit, if we have them,
17104                // instead of how they are now.
17105                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17106                // will take you back to where you made the last edit, instead of staying where you scrolled
17107                self.selection_history
17108                    .transaction(transaction_id_prev)
17109                    .map(|t| t.0.clone())
17110            })
17111            .unwrap_or_else(|| self.selections.disjoint_anchors());
17112
17113        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17114        let format = project.update(cx, |project, cx| {
17115            project.format(buffers, target, true, trigger, cx)
17116        });
17117
17118        cx.spawn_in(window, async move |editor, cx| {
17119            let transaction = futures::select_biased! {
17120                transaction = format.log_err().fuse() => transaction,
17121                () = timeout => {
17122                    log::warn!("timed out waiting for formatting");
17123                    None
17124                }
17125            };
17126
17127            buffer
17128                .update(cx, |buffer, cx| {
17129                    if let Some(transaction) = transaction
17130                        && !buffer.is_singleton()
17131                    {
17132                        buffer.push_transaction(&transaction.0, cx);
17133                    }
17134                    cx.notify();
17135                })
17136                .ok();
17137
17138            if let Some(transaction_id_now) =
17139                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17140            {
17141                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17142                if has_new_transaction {
17143                    _ = editor.update(cx, |editor, _| {
17144                        editor
17145                            .selection_history
17146                            .insert_transaction(transaction_id_now, selections_prev);
17147                    });
17148                }
17149            }
17150
17151            Ok(())
17152        })
17153    }
17154
17155    fn organize_imports(
17156        &mut self,
17157        _: &OrganizeImports,
17158        window: &mut Window,
17159        cx: &mut Context<Self>,
17160    ) -> Option<Task<Result<()>>> {
17161        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17162        let project = match &self.project {
17163            Some(project) => project.clone(),
17164            None => return None,
17165        };
17166        Some(self.perform_code_action_kind(
17167            project,
17168            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17169            window,
17170            cx,
17171        ))
17172    }
17173
17174    fn perform_code_action_kind(
17175        &mut self,
17176        project: Entity<Project>,
17177        kind: CodeActionKind,
17178        window: &mut Window,
17179        cx: &mut Context<Self>,
17180    ) -> Task<Result<()>> {
17181        let buffer = self.buffer.clone();
17182        let buffers = buffer.read(cx).all_buffers();
17183        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17184        let apply_action = project.update(cx, |project, cx| {
17185            project.apply_code_action_kind(buffers, kind, true, cx)
17186        });
17187        cx.spawn_in(window, async move |_, cx| {
17188            let transaction = futures::select_biased! {
17189                () = timeout => {
17190                    log::warn!("timed out waiting for executing code action");
17191                    None
17192                }
17193                transaction = apply_action.log_err().fuse() => transaction,
17194            };
17195            buffer
17196                .update(cx, |buffer, cx| {
17197                    // check if we need this
17198                    if let Some(transaction) = transaction
17199                        && !buffer.is_singleton()
17200                    {
17201                        buffer.push_transaction(&transaction.0, cx);
17202                    }
17203                    cx.notify();
17204                })
17205                .ok();
17206            Ok(())
17207        })
17208    }
17209
17210    pub fn restart_language_server(
17211        &mut self,
17212        _: &RestartLanguageServer,
17213        _: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) {
17216        if let Some(project) = self.project.clone() {
17217            self.buffer.update(cx, |multi_buffer, cx| {
17218                project.update(cx, |project, cx| {
17219                    project.restart_language_servers_for_buffers(
17220                        multi_buffer.all_buffers().into_iter().collect(),
17221                        HashSet::default(),
17222                        cx,
17223                    );
17224                });
17225            })
17226        }
17227    }
17228
17229    pub fn stop_language_server(
17230        &mut self,
17231        _: &StopLanguageServer,
17232        _: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        if let Some(project) = self.project.clone() {
17236            self.buffer.update(cx, |multi_buffer, cx| {
17237                project.update(cx, |project, cx| {
17238                    project.stop_language_servers_for_buffers(
17239                        multi_buffer.all_buffers().into_iter().collect(),
17240                        HashSet::default(),
17241                        cx,
17242                    );
17243                    cx.emit(project::Event::RefreshInlayHints);
17244                });
17245            });
17246        }
17247    }
17248
17249    fn cancel_language_server_work(
17250        workspace: &mut Workspace,
17251        _: &actions::CancelLanguageServerWork,
17252        _: &mut Window,
17253        cx: &mut Context<Workspace>,
17254    ) {
17255        let project = workspace.project();
17256        let buffers = workspace
17257            .active_item(cx)
17258            .and_then(|item| item.act_as::<Editor>(cx))
17259            .map_or(HashSet::default(), |editor| {
17260                editor.read(cx).buffer.read(cx).all_buffers()
17261            });
17262        project.update(cx, |project, cx| {
17263            project.cancel_language_server_work_for_buffers(buffers, cx);
17264        });
17265    }
17266
17267    fn show_character_palette(
17268        &mut self,
17269        _: &ShowCharacterPalette,
17270        window: &mut Window,
17271        _: &mut Context<Self>,
17272    ) {
17273        window.show_character_palette();
17274    }
17275
17276    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17277        if !self.diagnostics_enabled() {
17278            return;
17279        }
17280
17281        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17282            let buffer = self.buffer.read(cx).snapshot(cx);
17283            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17284            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17285            let is_valid = buffer
17286                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17287                .any(|entry| {
17288                    entry.diagnostic.is_primary
17289                        && !entry.range.is_empty()
17290                        && entry.range.start == primary_range_start
17291                        && entry.diagnostic.message == active_diagnostics.active_message
17292                });
17293
17294            if !is_valid {
17295                self.dismiss_diagnostics(cx);
17296            }
17297        }
17298    }
17299
17300    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17301        match &self.active_diagnostics {
17302            ActiveDiagnostic::Group(group) => Some(group),
17303            _ => None,
17304        }
17305    }
17306
17307    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17308        if !self.diagnostics_enabled() {
17309            return;
17310        }
17311        self.dismiss_diagnostics(cx);
17312        self.active_diagnostics = ActiveDiagnostic::All;
17313    }
17314
17315    fn activate_diagnostics(
17316        &mut self,
17317        buffer_id: BufferId,
17318        diagnostic: DiagnosticEntry<usize>,
17319        window: &mut Window,
17320        cx: &mut Context<Self>,
17321    ) {
17322        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17323            return;
17324        }
17325        self.dismiss_diagnostics(cx);
17326        let snapshot = self.snapshot(window, cx);
17327        let buffer = self.buffer.read(cx).snapshot(cx);
17328        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17329            return;
17330        };
17331
17332        let diagnostic_group = buffer
17333            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17334            .collect::<Vec<_>>();
17335
17336        let blocks =
17337            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17338
17339        let blocks = self.display_map.update(cx, |display_map, cx| {
17340            display_map.insert_blocks(blocks, cx).into_iter().collect()
17341        });
17342        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17343            active_range: buffer.anchor_before(diagnostic.range.start)
17344                ..buffer.anchor_after(diagnostic.range.end),
17345            active_message: diagnostic.diagnostic.message.clone(),
17346            group_id: diagnostic.diagnostic.group_id,
17347            blocks,
17348        });
17349        cx.notify();
17350    }
17351
17352    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17353        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17354            return;
17355        };
17356
17357        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17358        if let ActiveDiagnostic::Group(group) = prev {
17359            self.display_map.update(cx, |display_map, cx| {
17360                display_map.remove_blocks(group.blocks, cx);
17361            });
17362            cx.notify();
17363        }
17364    }
17365
17366    /// Disable inline diagnostics rendering for this editor.
17367    pub fn disable_inline_diagnostics(&mut self) {
17368        self.inline_diagnostics_enabled = false;
17369        self.inline_diagnostics_update = Task::ready(());
17370        self.inline_diagnostics.clear();
17371    }
17372
17373    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17374        self.diagnostics_enabled = false;
17375        self.dismiss_diagnostics(cx);
17376        self.inline_diagnostics_update = Task::ready(());
17377        self.inline_diagnostics.clear();
17378    }
17379
17380    pub fn disable_word_completions(&mut self) {
17381        self.word_completions_enabled = false;
17382    }
17383
17384    pub fn diagnostics_enabled(&self) -> bool {
17385        self.diagnostics_enabled && self.mode.is_full()
17386    }
17387
17388    pub fn inline_diagnostics_enabled(&self) -> bool {
17389        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17390    }
17391
17392    pub fn show_inline_diagnostics(&self) -> bool {
17393        self.show_inline_diagnostics
17394    }
17395
17396    pub fn toggle_inline_diagnostics(
17397        &mut self,
17398        _: &ToggleInlineDiagnostics,
17399        window: &mut Window,
17400        cx: &mut Context<Editor>,
17401    ) {
17402        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17403        self.refresh_inline_diagnostics(false, window, cx);
17404    }
17405
17406    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17407        self.diagnostics_max_severity = severity;
17408        self.display_map.update(cx, |display_map, _| {
17409            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17410        });
17411    }
17412
17413    pub fn toggle_diagnostics(
17414        &mut self,
17415        _: &ToggleDiagnostics,
17416        window: &mut Window,
17417        cx: &mut Context<Editor>,
17418    ) {
17419        if !self.diagnostics_enabled() {
17420            return;
17421        }
17422
17423        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17424            EditorSettings::get_global(cx)
17425                .diagnostics_max_severity
17426                .filter(|severity| severity != &DiagnosticSeverity::Off)
17427                .unwrap_or(DiagnosticSeverity::Hint)
17428        } else {
17429            DiagnosticSeverity::Off
17430        };
17431        self.set_max_diagnostics_severity(new_severity, cx);
17432        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17433            self.active_diagnostics = ActiveDiagnostic::None;
17434            self.inline_diagnostics_update = Task::ready(());
17435            self.inline_diagnostics.clear();
17436        } else {
17437            self.refresh_inline_diagnostics(false, window, cx);
17438        }
17439
17440        cx.notify();
17441    }
17442
17443    pub fn toggle_minimap(
17444        &mut self,
17445        _: &ToggleMinimap,
17446        window: &mut Window,
17447        cx: &mut Context<Editor>,
17448    ) {
17449        if self.supports_minimap(cx) {
17450            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17451        }
17452    }
17453
17454    fn refresh_inline_diagnostics(
17455        &mut self,
17456        debounce: bool,
17457        window: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) {
17460        let max_severity = ProjectSettings::get_global(cx)
17461            .diagnostics
17462            .inline
17463            .max_severity
17464            .unwrap_or(self.diagnostics_max_severity);
17465
17466        if !self.inline_diagnostics_enabled()
17467            || !self.show_inline_diagnostics
17468            || max_severity == DiagnosticSeverity::Off
17469        {
17470            self.inline_diagnostics_update = Task::ready(());
17471            self.inline_diagnostics.clear();
17472            return;
17473        }
17474
17475        let debounce_ms = ProjectSettings::get_global(cx)
17476            .diagnostics
17477            .inline
17478            .update_debounce_ms;
17479        let debounce = if debounce && debounce_ms > 0 {
17480            Some(Duration::from_millis(debounce_ms))
17481        } else {
17482            None
17483        };
17484        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17485            if let Some(debounce) = debounce {
17486                cx.background_executor().timer(debounce).await;
17487            }
17488            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17489                editor
17490                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17491                    .ok()
17492            }) else {
17493                return;
17494            };
17495
17496            let new_inline_diagnostics = cx
17497                .background_spawn(async move {
17498                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17499                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17500                        let message = diagnostic_entry
17501                            .diagnostic
17502                            .message
17503                            .split_once('\n')
17504                            .map(|(line, _)| line)
17505                            .map(SharedString::new)
17506                            .unwrap_or_else(|| {
17507                                SharedString::from(diagnostic_entry.diagnostic.message)
17508                            });
17509                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17510                        let (Ok(i) | Err(i)) = inline_diagnostics
17511                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17512                        inline_diagnostics.insert(
17513                            i,
17514                            (
17515                                start_anchor,
17516                                InlineDiagnostic {
17517                                    message,
17518                                    group_id: diagnostic_entry.diagnostic.group_id,
17519                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17520                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17521                                    severity: diagnostic_entry.diagnostic.severity,
17522                                },
17523                            ),
17524                        );
17525                    }
17526                    inline_diagnostics
17527                })
17528                .await;
17529
17530            editor
17531                .update(cx, |editor, cx| {
17532                    editor.inline_diagnostics = new_inline_diagnostics;
17533                    cx.notify();
17534                })
17535                .ok();
17536        });
17537    }
17538
17539    fn pull_diagnostics(
17540        &mut self,
17541        buffer_id: Option<BufferId>,
17542        window: &Window,
17543        cx: &mut Context<Self>,
17544    ) -> Option<()> {
17545        if !self.mode().is_full() {
17546            return None;
17547        }
17548        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17549            .diagnostics
17550            .lsp_pull_diagnostics;
17551        if !pull_diagnostics_settings.enabled {
17552            return None;
17553        }
17554        let project = self.project()?.downgrade();
17555        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17556        let mut buffers = self.buffer.read(cx).all_buffers();
17557        if let Some(buffer_id) = buffer_id {
17558            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17559        }
17560
17561        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17562            cx.background_executor().timer(debounce).await;
17563
17564            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17565                buffers
17566                    .into_iter()
17567                    .filter_map(|buffer| {
17568                        project
17569                            .update(cx, |project, cx| {
17570                                project.lsp_store().update(cx, |lsp_store, cx| {
17571                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17572                                })
17573                            })
17574                            .ok()
17575                    })
17576                    .collect::<FuturesUnordered<_>>()
17577            }) else {
17578                return;
17579            };
17580
17581            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17582                match pull_task {
17583                    Ok(()) => {
17584                        if editor
17585                            .update_in(cx, |editor, window, cx| {
17586                                editor.update_diagnostics_state(window, cx);
17587                            })
17588                            .is_err()
17589                        {
17590                            return;
17591                        }
17592                    }
17593                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17594                }
17595            }
17596        });
17597
17598        Some(())
17599    }
17600
17601    pub fn set_selections_from_remote(
17602        &mut self,
17603        selections: Vec<Selection<Anchor>>,
17604        pending_selection: Option<Selection<Anchor>>,
17605        window: &mut Window,
17606        cx: &mut Context<Self>,
17607    ) {
17608        let old_cursor_position = self.selections.newest_anchor().head();
17609        self.selections.change_with(cx, |s| {
17610            s.select_anchors(selections);
17611            if let Some(pending_selection) = pending_selection {
17612                s.set_pending(pending_selection, SelectMode::Character);
17613            } else {
17614                s.clear_pending();
17615            }
17616        });
17617        self.selections_did_change(
17618            false,
17619            &old_cursor_position,
17620            SelectionEffects::default(),
17621            window,
17622            cx,
17623        );
17624    }
17625
17626    pub fn transact(
17627        &mut self,
17628        window: &mut Window,
17629        cx: &mut Context<Self>,
17630        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17631    ) -> Option<TransactionId> {
17632        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17633            this.start_transaction_at(Instant::now(), window, cx);
17634            update(this, window, cx);
17635            this.end_transaction_at(Instant::now(), cx)
17636        })
17637    }
17638
17639    pub fn start_transaction_at(
17640        &mut self,
17641        now: Instant,
17642        window: &mut Window,
17643        cx: &mut Context<Self>,
17644    ) -> Option<TransactionId> {
17645        self.end_selection(window, cx);
17646        if let Some(tx_id) = self
17647            .buffer
17648            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17649        {
17650            self.selection_history
17651                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17652            cx.emit(EditorEvent::TransactionBegun {
17653                transaction_id: tx_id,
17654            });
17655            Some(tx_id)
17656        } else {
17657            None
17658        }
17659    }
17660
17661    pub fn end_transaction_at(
17662        &mut self,
17663        now: Instant,
17664        cx: &mut Context<Self>,
17665    ) -> Option<TransactionId> {
17666        if let Some(transaction_id) = self
17667            .buffer
17668            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17669        {
17670            if let Some((_, end_selections)) =
17671                self.selection_history.transaction_mut(transaction_id)
17672            {
17673                *end_selections = Some(self.selections.disjoint_anchors());
17674            } else {
17675                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17676            }
17677
17678            cx.emit(EditorEvent::Edited { transaction_id });
17679            Some(transaction_id)
17680        } else {
17681            None
17682        }
17683    }
17684
17685    pub fn modify_transaction_selection_history(
17686        &mut self,
17687        transaction_id: TransactionId,
17688        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17689    ) -> bool {
17690        self.selection_history
17691            .transaction_mut(transaction_id)
17692            .map(modify)
17693            .is_some()
17694    }
17695
17696    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17697        if self.selection_mark_mode {
17698            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17699                s.move_with(|_, sel| {
17700                    sel.collapse_to(sel.head(), SelectionGoal::None);
17701                });
17702            })
17703        }
17704        self.selection_mark_mode = true;
17705        cx.notify();
17706    }
17707
17708    pub fn swap_selection_ends(
17709        &mut self,
17710        _: &actions::SwapSelectionEnds,
17711        window: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17715            s.move_with(|_, sel| {
17716                if sel.start != sel.end {
17717                    sel.reversed = !sel.reversed
17718                }
17719            });
17720        });
17721        self.request_autoscroll(Autoscroll::newest(), cx);
17722        cx.notify();
17723    }
17724
17725    pub fn toggle_focus(
17726        workspace: &mut Workspace,
17727        _: &actions::ToggleFocus,
17728        window: &mut Window,
17729        cx: &mut Context<Workspace>,
17730    ) {
17731        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17732            return;
17733        };
17734        workspace.activate_item(&item, true, true, window, cx);
17735    }
17736
17737    pub fn toggle_fold(
17738        &mut self,
17739        _: &actions::ToggleFold,
17740        window: &mut Window,
17741        cx: &mut Context<Self>,
17742    ) {
17743        if self.is_singleton(cx) {
17744            let selection = self.selections.newest::<Point>(cx);
17745
17746            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17747            let range = if selection.is_empty() {
17748                let point = selection.head().to_display_point(&display_map);
17749                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17750                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17751                    .to_point(&display_map);
17752                start..end
17753            } else {
17754                selection.range()
17755            };
17756            if display_map.folds_in_range(range).next().is_some() {
17757                self.unfold_lines(&Default::default(), window, cx)
17758            } else {
17759                self.fold(&Default::default(), window, cx)
17760            }
17761        } else {
17762            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17763            let buffer_ids: HashSet<_> = self
17764                .selections
17765                .disjoint_anchor_ranges()
17766                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17767                .collect();
17768
17769            let should_unfold = buffer_ids
17770                .iter()
17771                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17772
17773            for buffer_id in buffer_ids {
17774                if should_unfold {
17775                    self.unfold_buffer(buffer_id, cx);
17776                } else {
17777                    self.fold_buffer(buffer_id, cx);
17778                }
17779            }
17780        }
17781    }
17782
17783    pub fn toggle_fold_recursive(
17784        &mut self,
17785        _: &actions::ToggleFoldRecursive,
17786        window: &mut Window,
17787        cx: &mut Context<Self>,
17788    ) {
17789        let selection = self.selections.newest::<Point>(cx);
17790
17791        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17792        let range = if selection.is_empty() {
17793            let point = selection.head().to_display_point(&display_map);
17794            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17795            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17796                .to_point(&display_map);
17797            start..end
17798        } else {
17799            selection.range()
17800        };
17801        if display_map.folds_in_range(range).next().is_some() {
17802            self.unfold_recursive(&Default::default(), window, cx)
17803        } else {
17804            self.fold_recursive(&Default::default(), window, cx)
17805        }
17806    }
17807
17808    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17809        if self.is_singleton(cx) {
17810            let mut to_fold = Vec::new();
17811            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17812            let selections = self.selections.all_adjusted(cx);
17813
17814            for selection in selections {
17815                let range = selection.range().sorted();
17816                let buffer_start_row = range.start.row;
17817
17818                if range.start.row != range.end.row {
17819                    let mut found = false;
17820                    let mut row = range.start.row;
17821                    while row <= range.end.row {
17822                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17823                        {
17824                            found = true;
17825                            row = crease.range().end.row + 1;
17826                            to_fold.push(crease);
17827                        } else {
17828                            row += 1
17829                        }
17830                    }
17831                    if found {
17832                        continue;
17833                    }
17834                }
17835
17836                for row in (0..=range.start.row).rev() {
17837                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17838                        && crease.range().end.row >= buffer_start_row
17839                    {
17840                        to_fold.push(crease);
17841                        if row <= range.start.row {
17842                            break;
17843                        }
17844                    }
17845                }
17846            }
17847
17848            self.fold_creases(to_fold, true, window, cx);
17849        } else {
17850            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17851            let buffer_ids = self
17852                .selections
17853                .disjoint_anchor_ranges()
17854                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17855                .collect::<HashSet<_>>();
17856            for buffer_id in buffer_ids {
17857                self.fold_buffer(buffer_id, cx);
17858            }
17859        }
17860    }
17861
17862    pub fn toggle_fold_all(
17863        &mut self,
17864        _: &actions::ToggleFoldAll,
17865        window: &mut Window,
17866        cx: &mut Context<Self>,
17867    ) {
17868        if self.buffer.read(cx).is_singleton() {
17869            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17870            let has_folds = display_map
17871                .folds_in_range(0..display_map.buffer_snapshot.len())
17872                .next()
17873                .is_some();
17874
17875            if has_folds {
17876                self.unfold_all(&actions::UnfoldAll, window, cx);
17877            } else {
17878                self.fold_all(&actions::FoldAll, window, cx);
17879            }
17880        } else {
17881            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17882            let should_unfold = buffer_ids
17883                .iter()
17884                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17885
17886            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17887                editor
17888                    .update_in(cx, |editor, _, cx| {
17889                        for buffer_id in buffer_ids {
17890                            if should_unfold {
17891                                editor.unfold_buffer(buffer_id, cx);
17892                            } else {
17893                                editor.fold_buffer(buffer_id, cx);
17894                            }
17895                        }
17896                    })
17897                    .ok();
17898            });
17899        }
17900    }
17901
17902    fn fold_at_level(
17903        &mut self,
17904        fold_at: &FoldAtLevel,
17905        window: &mut Window,
17906        cx: &mut Context<Self>,
17907    ) {
17908        if !self.buffer.read(cx).is_singleton() {
17909            return;
17910        }
17911
17912        let fold_at_level = fold_at.0;
17913        let snapshot = self.buffer.read(cx).snapshot(cx);
17914        let mut to_fold = Vec::new();
17915        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17916
17917        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17918            while start_row < end_row {
17919                match self
17920                    .snapshot(window, cx)
17921                    .crease_for_buffer_row(MultiBufferRow(start_row))
17922                {
17923                    Some(crease) => {
17924                        let nested_start_row = crease.range().start.row + 1;
17925                        let nested_end_row = crease.range().end.row;
17926
17927                        if current_level < fold_at_level {
17928                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17929                        } else if current_level == fold_at_level {
17930                            to_fold.push(crease);
17931                        }
17932
17933                        start_row = nested_end_row + 1;
17934                    }
17935                    None => start_row += 1,
17936                }
17937            }
17938        }
17939
17940        self.fold_creases(to_fold, true, window, cx);
17941    }
17942
17943    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17944        if self.buffer.read(cx).is_singleton() {
17945            let mut fold_ranges = Vec::new();
17946            let snapshot = self.buffer.read(cx).snapshot(cx);
17947
17948            for row in 0..snapshot.max_row().0 {
17949                if let Some(foldable_range) = self
17950                    .snapshot(window, cx)
17951                    .crease_for_buffer_row(MultiBufferRow(row))
17952                {
17953                    fold_ranges.push(foldable_range);
17954                }
17955            }
17956
17957            self.fold_creases(fold_ranges, true, window, cx);
17958        } else {
17959            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17960                editor
17961                    .update_in(cx, |editor, _, cx| {
17962                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17963                            editor.fold_buffer(buffer_id, cx);
17964                        }
17965                    })
17966                    .ok();
17967            });
17968        }
17969    }
17970
17971    pub fn fold_function_bodies(
17972        &mut self,
17973        _: &actions::FoldFunctionBodies,
17974        window: &mut Window,
17975        cx: &mut Context<Self>,
17976    ) {
17977        let snapshot = self.buffer.read(cx).snapshot(cx);
17978
17979        let ranges = snapshot
17980            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17981            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17982            .collect::<Vec<_>>();
17983
17984        let creases = ranges
17985            .into_iter()
17986            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17987            .collect();
17988
17989        self.fold_creases(creases, true, window, cx);
17990    }
17991
17992    pub fn fold_recursive(
17993        &mut self,
17994        _: &actions::FoldRecursive,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) {
17998        let mut to_fold = Vec::new();
17999        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18000        let selections = self.selections.all_adjusted(cx);
18001
18002        for selection in selections {
18003            let range = selection.range().sorted();
18004            let buffer_start_row = range.start.row;
18005
18006            if range.start.row != range.end.row {
18007                let mut found = false;
18008                for row in range.start.row..=range.end.row {
18009                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18010                        found = true;
18011                        to_fold.push(crease);
18012                    }
18013                }
18014                if found {
18015                    continue;
18016                }
18017            }
18018
18019            for row in (0..=range.start.row).rev() {
18020                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18021                    if crease.range().end.row >= buffer_start_row {
18022                        to_fold.push(crease);
18023                    } else {
18024                        break;
18025                    }
18026                }
18027            }
18028        }
18029
18030        self.fold_creases(to_fold, true, window, cx);
18031    }
18032
18033    pub fn fold_at(
18034        &mut self,
18035        buffer_row: MultiBufferRow,
18036        window: &mut Window,
18037        cx: &mut Context<Self>,
18038    ) {
18039        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18040
18041        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18042            let autoscroll = self
18043                .selections
18044                .all::<Point>(cx)
18045                .iter()
18046                .any(|selection| crease.range().overlaps(&selection.range()));
18047
18048            self.fold_creases(vec![crease], autoscroll, window, cx);
18049        }
18050    }
18051
18052    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18053        if self.is_singleton(cx) {
18054            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18055            let buffer = &display_map.buffer_snapshot;
18056            let selections = self.selections.all::<Point>(cx);
18057            let ranges = selections
18058                .iter()
18059                .map(|s| {
18060                    let range = s.display_range(&display_map).sorted();
18061                    let mut start = range.start.to_point(&display_map);
18062                    let mut end = range.end.to_point(&display_map);
18063                    start.column = 0;
18064                    end.column = buffer.line_len(MultiBufferRow(end.row));
18065                    start..end
18066                })
18067                .collect::<Vec<_>>();
18068
18069            self.unfold_ranges(&ranges, true, true, cx);
18070        } else {
18071            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18072            let buffer_ids = self
18073                .selections
18074                .disjoint_anchor_ranges()
18075                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18076                .collect::<HashSet<_>>();
18077            for buffer_id in buffer_ids {
18078                self.unfold_buffer(buffer_id, cx);
18079            }
18080        }
18081    }
18082
18083    pub fn unfold_recursive(
18084        &mut self,
18085        _: &UnfoldRecursive,
18086        _window: &mut Window,
18087        cx: &mut Context<Self>,
18088    ) {
18089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18090        let selections = self.selections.all::<Point>(cx);
18091        let ranges = selections
18092            .iter()
18093            .map(|s| {
18094                let mut range = s.display_range(&display_map).sorted();
18095                *range.start.column_mut() = 0;
18096                *range.end.column_mut() = display_map.line_len(range.end.row());
18097                let start = range.start.to_point(&display_map);
18098                let end = range.end.to_point(&display_map);
18099                start..end
18100            })
18101            .collect::<Vec<_>>();
18102
18103        self.unfold_ranges(&ranges, true, true, cx);
18104    }
18105
18106    pub fn unfold_at(
18107        &mut self,
18108        buffer_row: MultiBufferRow,
18109        _window: &mut Window,
18110        cx: &mut Context<Self>,
18111    ) {
18112        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18113
18114        let intersection_range = Point::new(buffer_row.0, 0)
18115            ..Point::new(
18116                buffer_row.0,
18117                display_map.buffer_snapshot.line_len(buffer_row),
18118            );
18119
18120        let autoscroll = self
18121            .selections
18122            .all::<Point>(cx)
18123            .iter()
18124            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18125
18126        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18127    }
18128
18129    pub fn unfold_all(
18130        &mut self,
18131        _: &actions::UnfoldAll,
18132        _window: &mut Window,
18133        cx: &mut Context<Self>,
18134    ) {
18135        if self.buffer.read(cx).is_singleton() {
18136            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18137            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18138        } else {
18139            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18140                editor
18141                    .update(cx, |editor, cx| {
18142                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18143                            editor.unfold_buffer(buffer_id, cx);
18144                        }
18145                    })
18146                    .ok();
18147            });
18148        }
18149    }
18150
18151    pub fn fold_selected_ranges(
18152        &mut self,
18153        _: &FoldSelectedRanges,
18154        window: &mut Window,
18155        cx: &mut Context<Self>,
18156    ) {
18157        let selections = self.selections.all_adjusted(cx);
18158        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18159        let ranges = selections
18160            .into_iter()
18161            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18162            .collect::<Vec<_>>();
18163        self.fold_creases(ranges, true, window, cx);
18164    }
18165
18166    pub fn fold_ranges<T: ToOffset + Clone>(
18167        &mut self,
18168        ranges: Vec<Range<T>>,
18169        auto_scroll: bool,
18170        window: &mut Window,
18171        cx: &mut Context<Self>,
18172    ) {
18173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18174        let ranges = ranges
18175            .into_iter()
18176            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18177            .collect::<Vec<_>>();
18178        self.fold_creases(ranges, auto_scroll, window, cx);
18179    }
18180
18181    pub fn fold_creases<T: ToOffset + Clone>(
18182        &mut self,
18183        creases: Vec<Crease<T>>,
18184        auto_scroll: bool,
18185        _window: &mut Window,
18186        cx: &mut Context<Self>,
18187    ) {
18188        if creases.is_empty() {
18189            return;
18190        }
18191
18192        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18193
18194        if auto_scroll {
18195            self.request_autoscroll(Autoscroll::fit(), cx);
18196        }
18197
18198        cx.notify();
18199
18200        self.scrollbar_marker_state.dirty = true;
18201        self.folds_did_change(cx);
18202    }
18203
18204    /// Removes any folds whose ranges intersect any of the given ranges.
18205    pub fn unfold_ranges<T: ToOffset + Clone>(
18206        &mut self,
18207        ranges: &[Range<T>],
18208        inclusive: bool,
18209        auto_scroll: bool,
18210        cx: &mut Context<Self>,
18211    ) {
18212        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18213            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18214        });
18215        self.folds_did_change(cx);
18216    }
18217
18218    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18219        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18220            return;
18221        }
18222        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18223        self.display_map.update(cx, |display_map, cx| {
18224            display_map.fold_buffers([buffer_id], cx)
18225        });
18226        cx.emit(EditorEvent::BufferFoldToggled {
18227            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18228            folded: true,
18229        });
18230        cx.notify();
18231    }
18232
18233    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18234        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18235            return;
18236        }
18237        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18238        self.display_map.update(cx, |display_map, cx| {
18239            display_map.unfold_buffers([buffer_id], cx);
18240        });
18241        cx.emit(EditorEvent::BufferFoldToggled {
18242            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18243            folded: false,
18244        });
18245        cx.notify();
18246    }
18247
18248    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18249        self.display_map.read(cx).is_buffer_folded(buffer)
18250    }
18251
18252    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18253        self.display_map.read(cx).folded_buffers()
18254    }
18255
18256    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18257        self.display_map.update(cx, |display_map, cx| {
18258            display_map.disable_header_for_buffer(buffer_id, cx);
18259        });
18260        cx.notify();
18261    }
18262
18263    /// Removes any folds with the given ranges.
18264    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18265        &mut self,
18266        ranges: &[Range<T>],
18267        type_id: TypeId,
18268        auto_scroll: bool,
18269        cx: &mut Context<Self>,
18270    ) {
18271        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18272            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18273        });
18274        self.folds_did_change(cx);
18275    }
18276
18277    fn remove_folds_with<T: ToOffset + Clone>(
18278        &mut self,
18279        ranges: &[Range<T>],
18280        auto_scroll: bool,
18281        cx: &mut Context<Self>,
18282        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18283    ) {
18284        if ranges.is_empty() {
18285            return;
18286        }
18287
18288        let mut buffers_affected = HashSet::default();
18289        let multi_buffer = self.buffer().read(cx);
18290        for range in ranges {
18291            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18292                buffers_affected.insert(buffer.read(cx).remote_id());
18293            };
18294        }
18295
18296        self.display_map.update(cx, update);
18297
18298        if auto_scroll {
18299            self.request_autoscroll(Autoscroll::fit(), cx);
18300        }
18301
18302        cx.notify();
18303        self.scrollbar_marker_state.dirty = true;
18304        self.active_indent_guides_state.dirty = true;
18305    }
18306
18307    pub fn update_renderer_widths(
18308        &mut self,
18309        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18310        cx: &mut Context<Self>,
18311    ) -> bool {
18312        self.display_map
18313            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18314    }
18315
18316    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18317        self.display_map.read(cx).fold_placeholder.clone()
18318    }
18319
18320    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18321        self.buffer.update(cx, |buffer, cx| {
18322            buffer.set_all_diff_hunks_expanded(cx);
18323        });
18324    }
18325
18326    pub fn expand_all_diff_hunks(
18327        &mut self,
18328        _: &ExpandAllDiffHunks,
18329        _window: &mut Window,
18330        cx: &mut Context<Self>,
18331    ) {
18332        self.buffer.update(cx, |buffer, cx| {
18333            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18334        });
18335    }
18336
18337    pub fn toggle_selected_diff_hunks(
18338        &mut self,
18339        _: &ToggleSelectedDiffHunks,
18340        _window: &mut Window,
18341        cx: &mut Context<Self>,
18342    ) {
18343        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18344        self.toggle_diff_hunks_in_ranges(ranges, cx);
18345    }
18346
18347    pub fn diff_hunks_in_ranges<'a>(
18348        &'a self,
18349        ranges: &'a [Range<Anchor>],
18350        buffer: &'a MultiBufferSnapshot,
18351    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18352        ranges.iter().flat_map(move |range| {
18353            let end_excerpt_id = range.end.excerpt_id;
18354            let range = range.to_point(buffer);
18355            let mut peek_end = range.end;
18356            if range.end.row < buffer.max_row().0 {
18357                peek_end = Point::new(range.end.row + 1, 0);
18358            }
18359            buffer
18360                .diff_hunks_in_range(range.start..peek_end)
18361                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18362        })
18363    }
18364
18365    pub fn has_stageable_diff_hunks_in_ranges(
18366        &self,
18367        ranges: &[Range<Anchor>],
18368        snapshot: &MultiBufferSnapshot,
18369    ) -> bool {
18370        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18371        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18372    }
18373
18374    pub fn toggle_staged_selected_diff_hunks(
18375        &mut self,
18376        _: &::git::ToggleStaged,
18377        _: &mut Window,
18378        cx: &mut Context<Self>,
18379    ) {
18380        let snapshot = self.buffer.read(cx).snapshot(cx);
18381        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18382        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18383        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18384    }
18385
18386    pub fn set_render_diff_hunk_controls(
18387        &mut self,
18388        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18389        cx: &mut Context<Self>,
18390    ) {
18391        self.render_diff_hunk_controls = render_diff_hunk_controls;
18392        cx.notify();
18393    }
18394
18395    pub fn stage_and_next(
18396        &mut self,
18397        _: &::git::StageAndNext,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        self.do_stage_or_unstage_and_next(true, window, cx);
18402    }
18403
18404    pub fn unstage_and_next(
18405        &mut self,
18406        _: &::git::UnstageAndNext,
18407        window: &mut Window,
18408        cx: &mut Context<Self>,
18409    ) {
18410        self.do_stage_or_unstage_and_next(false, window, cx);
18411    }
18412
18413    pub fn stage_or_unstage_diff_hunks(
18414        &mut self,
18415        stage: bool,
18416        ranges: Vec<Range<Anchor>>,
18417        cx: &mut Context<Self>,
18418    ) {
18419        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18420        cx.spawn(async move |this, cx| {
18421            task.await?;
18422            this.update(cx, |this, cx| {
18423                let snapshot = this.buffer.read(cx).snapshot(cx);
18424                let chunk_by = this
18425                    .diff_hunks_in_ranges(&ranges, &snapshot)
18426                    .chunk_by(|hunk| hunk.buffer_id);
18427                for (buffer_id, hunks) in &chunk_by {
18428                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18429                }
18430            })
18431        })
18432        .detach_and_log_err(cx);
18433    }
18434
18435    fn save_buffers_for_ranges_if_needed(
18436        &mut self,
18437        ranges: &[Range<Anchor>],
18438        cx: &mut Context<Editor>,
18439    ) -> Task<Result<()>> {
18440        let multibuffer = self.buffer.read(cx);
18441        let snapshot = multibuffer.read(cx);
18442        let buffer_ids: HashSet<_> = ranges
18443            .iter()
18444            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18445            .collect();
18446        drop(snapshot);
18447
18448        let mut buffers = HashSet::default();
18449        for buffer_id in buffer_ids {
18450            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18451                let buffer = buffer_entity.read(cx);
18452                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18453                {
18454                    buffers.insert(buffer_entity);
18455                }
18456            }
18457        }
18458
18459        if let Some(project) = &self.project {
18460            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18461        } else {
18462            Task::ready(Ok(()))
18463        }
18464    }
18465
18466    fn do_stage_or_unstage_and_next(
18467        &mut self,
18468        stage: bool,
18469        window: &mut Window,
18470        cx: &mut Context<Self>,
18471    ) {
18472        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18473
18474        if ranges.iter().any(|range| range.start != range.end) {
18475            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18476            return;
18477        }
18478
18479        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18480        let snapshot = self.snapshot(window, cx);
18481        let position = self.selections.newest::<Point>(cx).head();
18482        let mut row = snapshot
18483            .buffer_snapshot
18484            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18485            .find(|hunk| hunk.row_range.start.0 > position.row)
18486            .map(|hunk| hunk.row_range.start);
18487
18488        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18489        // Outside of the project diff editor, wrap around to the beginning.
18490        if !all_diff_hunks_expanded {
18491            row = row.or_else(|| {
18492                snapshot
18493                    .buffer_snapshot
18494                    .diff_hunks_in_range(Point::zero()..position)
18495                    .find(|hunk| hunk.row_range.end.0 < position.row)
18496                    .map(|hunk| hunk.row_range.start)
18497            });
18498        }
18499
18500        if let Some(row) = row {
18501            let destination = Point::new(row.0, 0);
18502            let autoscroll = Autoscroll::center();
18503
18504            self.unfold_ranges(&[destination..destination], false, false, cx);
18505            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18506                s.select_ranges([destination..destination]);
18507            });
18508        }
18509    }
18510
18511    fn do_stage_or_unstage(
18512        &self,
18513        stage: bool,
18514        buffer_id: BufferId,
18515        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18516        cx: &mut App,
18517    ) -> Option<()> {
18518        let project = self.project()?;
18519        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18520        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18521        let buffer_snapshot = buffer.read(cx).snapshot();
18522        let file_exists = buffer_snapshot
18523            .file()
18524            .is_some_and(|file| file.disk_state().exists());
18525        diff.update(cx, |diff, cx| {
18526            diff.stage_or_unstage_hunks(
18527                stage,
18528                &hunks
18529                    .map(|hunk| buffer_diff::DiffHunk {
18530                        buffer_range: hunk.buffer_range,
18531                        diff_base_byte_range: hunk.diff_base_byte_range,
18532                        secondary_status: hunk.secondary_status,
18533                        range: Point::zero()..Point::zero(), // unused
18534                    })
18535                    .collect::<Vec<_>>(),
18536                &buffer_snapshot,
18537                file_exists,
18538                cx,
18539            )
18540        });
18541        None
18542    }
18543
18544    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18545        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18546        self.buffer
18547            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18548    }
18549
18550    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18551        self.buffer.update(cx, |buffer, cx| {
18552            let ranges = vec![Anchor::min()..Anchor::max()];
18553            if !buffer.all_diff_hunks_expanded()
18554                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18555            {
18556                buffer.collapse_diff_hunks(ranges, cx);
18557                true
18558            } else {
18559                false
18560            }
18561        })
18562    }
18563
18564    fn toggle_diff_hunks_in_ranges(
18565        &mut self,
18566        ranges: Vec<Range<Anchor>>,
18567        cx: &mut Context<Editor>,
18568    ) {
18569        self.buffer.update(cx, |buffer, cx| {
18570            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18571            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18572        })
18573    }
18574
18575    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18576        self.buffer.update(cx, |buffer, cx| {
18577            let snapshot = buffer.snapshot(cx);
18578            let excerpt_id = range.end.excerpt_id;
18579            let point_range = range.to_point(&snapshot);
18580            let expand = !buffer.single_hunk_is_expanded(range, cx);
18581            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18582        })
18583    }
18584
18585    pub(crate) fn apply_all_diff_hunks(
18586        &mut self,
18587        _: &ApplyAllDiffHunks,
18588        window: &mut Window,
18589        cx: &mut Context<Self>,
18590    ) {
18591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18592
18593        let buffers = self.buffer.read(cx).all_buffers();
18594        for branch_buffer in buffers {
18595            branch_buffer.update(cx, |branch_buffer, cx| {
18596                branch_buffer.merge_into_base(Vec::new(), cx);
18597            });
18598        }
18599
18600        if let Some(project) = self.project.clone() {
18601            self.save(
18602                SaveOptions {
18603                    format: true,
18604                    autosave: false,
18605                },
18606                project,
18607                window,
18608                cx,
18609            )
18610            .detach_and_log_err(cx);
18611        }
18612    }
18613
18614    pub(crate) fn apply_selected_diff_hunks(
18615        &mut self,
18616        _: &ApplyDiffHunk,
18617        window: &mut Window,
18618        cx: &mut Context<Self>,
18619    ) {
18620        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18621        let snapshot = self.snapshot(window, cx);
18622        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18623        let mut ranges_by_buffer = HashMap::default();
18624        self.transact(window, cx, |editor, _window, cx| {
18625            for hunk in hunks {
18626                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18627                    ranges_by_buffer
18628                        .entry(buffer.clone())
18629                        .or_insert_with(Vec::new)
18630                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18631                }
18632            }
18633
18634            for (buffer, ranges) in ranges_by_buffer {
18635                buffer.update(cx, |buffer, cx| {
18636                    buffer.merge_into_base(ranges, cx);
18637                });
18638            }
18639        });
18640
18641        if let Some(project) = self.project.clone() {
18642            self.save(
18643                SaveOptions {
18644                    format: true,
18645                    autosave: false,
18646                },
18647                project,
18648                window,
18649                cx,
18650            )
18651            .detach_and_log_err(cx);
18652        }
18653    }
18654
18655    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18656        if hovered != self.gutter_hovered {
18657            self.gutter_hovered = hovered;
18658            cx.notify();
18659        }
18660    }
18661
18662    pub fn insert_blocks(
18663        &mut self,
18664        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18665        autoscroll: Option<Autoscroll>,
18666        cx: &mut Context<Self>,
18667    ) -> Vec<CustomBlockId> {
18668        let blocks = self
18669            .display_map
18670            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18671        if let Some(autoscroll) = autoscroll {
18672            self.request_autoscroll(autoscroll, cx);
18673        }
18674        cx.notify();
18675        blocks
18676    }
18677
18678    pub fn resize_blocks(
18679        &mut self,
18680        heights: HashMap<CustomBlockId, u32>,
18681        autoscroll: Option<Autoscroll>,
18682        cx: &mut Context<Self>,
18683    ) {
18684        self.display_map
18685            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18686        if let Some(autoscroll) = autoscroll {
18687            self.request_autoscroll(autoscroll, cx);
18688        }
18689        cx.notify();
18690    }
18691
18692    pub fn replace_blocks(
18693        &mut self,
18694        renderers: HashMap<CustomBlockId, RenderBlock>,
18695        autoscroll: Option<Autoscroll>,
18696        cx: &mut Context<Self>,
18697    ) {
18698        self.display_map
18699            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18700        if let Some(autoscroll) = autoscroll {
18701            self.request_autoscroll(autoscroll, cx);
18702        }
18703        cx.notify();
18704    }
18705
18706    pub fn remove_blocks(
18707        &mut self,
18708        block_ids: HashSet<CustomBlockId>,
18709        autoscroll: Option<Autoscroll>,
18710        cx: &mut Context<Self>,
18711    ) {
18712        self.display_map.update(cx, |display_map, cx| {
18713            display_map.remove_blocks(block_ids, cx)
18714        });
18715        if let Some(autoscroll) = autoscroll {
18716            self.request_autoscroll(autoscroll, cx);
18717        }
18718        cx.notify();
18719    }
18720
18721    pub fn row_for_block(
18722        &self,
18723        block_id: CustomBlockId,
18724        cx: &mut Context<Self>,
18725    ) -> Option<DisplayRow> {
18726        self.display_map
18727            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18728    }
18729
18730    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18731        self.focused_block = Some(focused_block);
18732    }
18733
18734    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18735        self.focused_block.take()
18736    }
18737
18738    pub fn insert_creases(
18739        &mut self,
18740        creases: impl IntoIterator<Item = Crease<Anchor>>,
18741        cx: &mut Context<Self>,
18742    ) -> Vec<CreaseId> {
18743        self.display_map
18744            .update(cx, |map, cx| map.insert_creases(creases, cx))
18745    }
18746
18747    pub fn remove_creases(
18748        &mut self,
18749        ids: impl IntoIterator<Item = CreaseId>,
18750        cx: &mut Context<Self>,
18751    ) -> Vec<(CreaseId, Range<Anchor>)> {
18752        self.display_map
18753            .update(cx, |map, cx| map.remove_creases(ids, cx))
18754    }
18755
18756    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18757        self.display_map
18758            .update(cx, |map, cx| map.snapshot(cx))
18759            .longest_row()
18760    }
18761
18762    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18763        self.display_map
18764            .update(cx, |map, cx| map.snapshot(cx))
18765            .max_point()
18766    }
18767
18768    pub fn text(&self, cx: &App) -> String {
18769        self.buffer.read(cx).read(cx).text()
18770    }
18771
18772    pub fn is_empty(&self, cx: &App) -> bool {
18773        self.buffer.read(cx).read(cx).is_empty()
18774    }
18775
18776    pub fn text_option(&self, cx: &App) -> Option<String> {
18777        let text = self.text(cx);
18778        let text = text.trim();
18779
18780        if text.is_empty() {
18781            return None;
18782        }
18783
18784        Some(text.to_string())
18785    }
18786
18787    pub fn set_text(
18788        &mut self,
18789        text: impl Into<Arc<str>>,
18790        window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) {
18793        self.transact(window, cx, |this, _, cx| {
18794            this.buffer
18795                .read(cx)
18796                .as_singleton()
18797                .expect("you can only call set_text on editors for singleton buffers")
18798                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18799        });
18800    }
18801
18802    pub fn display_text(&self, cx: &mut App) -> String {
18803        self.display_map
18804            .update(cx, |map, cx| map.snapshot(cx))
18805            .text()
18806    }
18807
18808    fn create_minimap(
18809        &self,
18810        minimap_settings: MinimapSettings,
18811        window: &mut Window,
18812        cx: &mut Context<Self>,
18813    ) -> Option<Entity<Self>> {
18814        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18815            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18816    }
18817
18818    fn initialize_new_minimap(
18819        &self,
18820        minimap_settings: MinimapSettings,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) -> Entity<Self> {
18824        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18825
18826        let mut minimap = Editor::new_internal(
18827            EditorMode::Minimap {
18828                parent: cx.weak_entity(),
18829            },
18830            self.buffer.clone(),
18831            None,
18832            Some(self.display_map.clone()),
18833            window,
18834            cx,
18835        );
18836        minimap.scroll_manager.clone_state(&self.scroll_manager);
18837        minimap.set_text_style_refinement(TextStyleRefinement {
18838            font_size: Some(MINIMAP_FONT_SIZE),
18839            font_weight: Some(MINIMAP_FONT_WEIGHT),
18840            ..Default::default()
18841        });
18842        minimap.update_minimap_configuration(minimap_settings, cx);
18843        cx.new(|_| minimap)
18844    }
18845
18846    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18847        let current_line_highlight = minimap_settings
18848            .current_line_highlight
18849            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18850        self.set_current_line_highlight(Some(current_line_highlight));
18851    }
18852
18853    pub fn minimap(&self) -> Option<&Entity<Self>> {
18854        self.minimap
18855            .as_ref()
18856            .filter(|_| self.minimap_visibility.visible())
18857    }
18858
18859    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18860        let mut wrap_guides = smallvec![];
18861
18862        if self.show_wrap_guides == Some(false) {
18863            return wrap_guides;
18864        }
18865
18866        let settings = self.buffer.read(cx).language_settings(cx);
18867        if settings.show_wrap_guides {
18868            match self.soft_wrap_mode(cx) {
18869                SoftWrap::Column(soft_wrap) => {
18870                    wrap_guides.push((soft_wrap as usize, true));
18871                }
18872                SoftWrap::Bounded(soft_wrap) => {
18873                    wrap_guides.push((soft_wrap as usize, true));
18874                }
18875                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18876            }
18877            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18878        }
18879
18880        wrap_guides
18881    }
18882
18883    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18884        let settings = self.buffer.read(cx).language_settings(cx);
18885        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18886        match mode {
18887            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18888                SoftWrap::None
18889            }
18890            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18891            language_settings::SoftWrap::PreferredLineLength => {
18892                SoftWrap::Column(settings.preferred_line_length)
18893            }
18894            language_settings::SoftWrap::Bounded => {
18895                SoftWrap::Bounded(settings.preferred_line_length)
18896            }
18897        }
18898    }
18899
18900    pub fn set_soft_wrap_mode(
18901        &mut self,
18902        mode: language_settings::SoftWrap,
18903
18904        cx: &mut Context<Self>,
18905    ) {
18906        self.soft_wrap_mode_override = Some(mode);
18907        cx.notify();
18908    }
18909
18910    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18911        self.hard_wrap = hard_wrap;
18912        cx.notify();
18913    }
18914
18915    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18916        self.text_style_refinement = Some(style);
18917    }
18918
18919    /// called by the Element so we know what style we were most recently rendered with.
18920    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18921        // We intentionally do not inform the display map about the minimap style
18922        // so that wrapping is not recalculated and stays consistent for the editor
18923        // and its linked minimap.
18924        if !self.mode.is_minimap() {
18925            let font = style.text.font();
18926            let font_size = style.text.font_size.to_pixels(window.rem_size());
18927            let display_map = self
18928                .placeholder_display_map
18929                .as_ref()
18930                .filter(|_| self.is_empty(cx))
18931                .unwrap_or(&self.display_map);
18932
18933            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18934        }
18935        self.style = Some(style);
18936    }
18937
18938    pub fn style(&self) -> Option<&EditorStyle> {
18939        self.style.as_ref()
18940    }
18941
18942    // Called by the element. This method is not designed to be called outside of the editor
18943    // element's layout code because it does not notify when rewrapping is computed synchronously.
18944    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18945        if self.is_empty(cx) {
18946            self.placeholder_display_map
18947                .as_ref()
18948                .map_or(false, |display_map| {
18949                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18950                })
18951        } else {
18952            self.display_map
18953                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18954        }
18955    }
18956
18957    pub fn set_soft_wrap(&mut self) {
18958        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18959    }
18960
18961    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18962        if self.soft_wrap_mode_override.is_some() {
18963            self.soft_wrap_mode_override.take();
18964        } else {
18965            let soft_wrap = match self.soft_wrap_mode(cx) {
18966                SoftWrap::GitDiff => return,
18967                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18968                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18969                    language_settings::SoftWrap::None
18970                }
18971            };
18972            self.soft_wrap_mode_override = Some(soft_wrap);
18973        }
18974        cx.notify();
18975    }
18976
18977    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18978        let Some(workspace) = self.workspace() else {
18979            return;
18980        };
18981        let fs = workspace.read(cx).app_state().fs.clone();
18982        let current_show = TabBarSettings::get_global(cx).show;
18983        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18984            setting.show = Some(!current_show);
18985        });
18986    }
18987
18988    pub fn toggle_indent_guides(
18989        &mut self,
18990        _: &ToggleIndentGuides,
18991        _: &mut Window,
18992        cx: &mut Context<Self>,
18993    ) {
18994        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18995            self.buffer
18996                .read(cx)
18997                .language_settings(cx)
18998                .indent_guides
18999                .enabled
19000        });
19001        self.show_indent_guides = Some(!currently_enabled);
19002        cx.notify();
19003    }
19004
19005    fn should_show_indent_guides(&self) -> Option<bool> {
19006        self.show_indent_guides
19007    }
19008
19009    pub fn toggle_line_numbers(
19010        &mut self,
19011        _: &ToggleLineNumbers,
19012        _: &mut Window,
19013        cx: &mut Context<Self>,
19014    ) {
19015        let mut editor_settings = EditorSettings::get_global(cx).clone();
19016        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19017        EditorSettings::override_global(editor_settings, cx);
19018    }
19019
19020    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19021        if let Some(show_line_numbers) = self.show_line_numbers {
19022            return show_line_numbers;
19023        }
19024        EditorSettings::get_global(cx).gutter.line_numbers
19025    }
19026
19027    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19028        self.use_relative_line_numbers
19029            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19030    }
19031
19032    pub fn toggle_relative_line_numbers(
19033        &mut self,
19034        _: &ToggleRelativeLineNumbers,
19035        _: &mut Window,
19036        cx: &mut Context<Self>,
19037    ) {
19038        let is_relative = self.should_use_relative_line_numbers(cx);
19039        self.set_relative_line_number(Some(!is_relative), cx)
19040    }
19041
19042    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19043        self.use_relative_line_numbers = is_relative;
19044        cx.notify();
19045    }
19046
19047    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19048        self.show_gutter = show_gutter;
19049        cx.notify();
19050    }
19051
19052    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19053        self.show_scrollbars = ScrollbarAxes {
19054            horizontal: show,
19055            vertical: show,
19056        };
19057        cx.notify();
19058    }
19059
19060    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19061        self.show_scrollbars.vertical = show;
19062        cx.notify();
19063    }
19064
19065    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19066        self.show_scrollbars.horizontal = show;
19067        cx.notify();
19068    }
19069
19070    pub fn set_minimap_visibility(
19071        &mut self,
19072        minimap_visibility: MinimapVisibility,
19073        window: &mut Window,
19074        cx: &mut Context<Self>,
19075    ) {
19076        if self.minimap_visibility != minimap_visibility {
19077            if minimap_visibility.visible() && self.minimap.is_none() {
19078                let minimap_settings = EditorSettings::get_global(cx).minimap;
19079                self.minimap =
19080                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19081            }
19082            self.minimap_visibility = minimap_visibility;
19083            cx.notify();
19084        }
19085    }
19086
19087    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19088        self.set_show_scrollbars(false, cx);
19089        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19090    }
19091
19092    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19093        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19094    }
19095
19096    /// Normally the text in full mode and auto height editors is padded on the
19097    /// left side by roughly half a character width for improved hit testing.
19098    ///
19099    /// Use this method to disable this for cases where this is not wanted (e.g.
19100    /// if you want to align the editor text with some other text above or below)
19101    /// or if you want to add this padding to single-line editors.
19102    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19103        self.offset_content = offset_content;
19104        cx.notify();
19105    }
19106
19107    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19108        self.show_line_numbers = Some(show_line_numbers);
19109        cx.notify();
19110    }
19111
19112    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19113        self.disable_expand_excerpt_buttons = true;
19114        cx.notify();
19115    }
19116
19117    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19118        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19119        cx.notify();
19120    }
19121
19122    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19123        self.show_code_actions = Some(show_code_actions);
19124        cx.notify();
19125    }
19126
19127    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19128        self.show_runnables = Some(show_runnables);
19129        cx.notify();
19130    }
19131
19132    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19133        self.show_breakpoints = Some(show_breakpoints);
19134        cx.notify();
19135    }
19136
19137    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19138        if self.display_map.read(cx).masked != masked {
19139            self.display_map.update(cx, |map, _| map.masked = masked);
19140        }
19141        cx.notify()
19142    }
19143
19144    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19145        self.show_wrap_guides = Some(show_wrap_guides);
19146        cx.notify();
19147    }
19148
19149    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19150        self.show_indent_guides = Some(show_indent_guides);
19151        cx.notify();
19152    }
19153
19154    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19155        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19156            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19157                && let Some(dir) = file.abs_path(cx).parent()
19158            {
19159                return Some(dir.to_owned());
19160            }
19161
19162            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19163                return Some(project_path.path.to_path_buf());
19164            }
19165        }
19166
19167        None
19168    }
19169
19170    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19171        self.active_excerpt(cx)?
19172            .1
19173            .read(cx)
19174            .file()
19175            .and_then(|f| f.as_local())
19176    }
19177
19178    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19179        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19180            let buffer = buffer.read(cx);
19181            if let Some(project_path) = buffer.project_path(cx) {
19182                let project = self.project()?.read(cx);
19183                project.absolute_path(&project_path, cx)
19184            } else {
19185                buffer
19186                    .file()
19187                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19188            }
19189        })
19190    }
19191
19192    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19193        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19194            let project_path = buffer.read(cx).project_path(cx)?;
19195            let project = self.project()?.read(cx);
19196            let entry = project.entry_for_path(&project_path, cx)?;
19197            let path = entry.path.to_path_buf();
19198            Some(path)
19199        })
19200    }
19201
19202    pub fn reveal_in_finder(
19203        &mut self,
19204        _: &RevealInFileManager,
19205        _window: &mut Window,
19206        cx: &mut Context<Self>,
19207    ) {
19208        if let Some(target) = self.target_file(cx) {
19209            cx.reveal_path(&target.abs_path(cx));
19210        }
19211    }
19212
19213    pub fn copy_path(
19214        &mut self,
19215        _: &zed_actions::workspace::CopyPath,
19216        _window: &mut Window,
19217        cx: &mut Context<Self>,
19218    ) {
19219        if let Some(path) = self.target_file_abs_path(cx)
19220            && let Some(path) = path.to_str()
19221        {
19222            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19223        }
19224    }
19225
19226    pub fn copy_relative_path(
19227        &mut self,
19228        _: &zed_actions::workspace::CopyRelativePath,
19229        _window: &mut Window,
19230        cx: &mut Context<Self>,
19231    ) {
19232        if let Some(path) = self.target_file_path(cx)
19233            && let Some(path) = path.to_str()
19234        {
19235            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19236        }
19237    }
19238
19239    /// Returns the project path for the editor's buffer, if any buffer is
19240    /// opened in the editor.
19241    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19242        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19243            buffer.read(cx).project_path(cx)
19244        } else {
19245            None
19246        }
19247    }
19248
19249    // Returns true if the editor handled a go-to-line request
19250    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19251        maybe!({
19252            let breakpoint_store = self.breakpoint_store.as_ref()?;
19253
19254            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19255            else {
19256                self.clear_row_highlights::<ActiveDebugLine>();
19257                return None;
19258            };
19259
19260            let position = active_stack_frame.position;
19261            let buffer_id = position.buffer_id?;
19262            let snapshot = self
19263                .project
19264                .as_ref()?
19265                .read(cx)
19266                .buffer_for_id(buffer_id, cx)?
19267                .read(cx)
19268                .snapshot();
19269
19270            let mut handled = false;
19271            for (id, ExcerptRange { context, .. }) in
19272                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19273            {
19274                if context.start.cmp(&position, &snapshot).is_ge()
19275                    || context.end.cmp(&position, &snapshot).is_lt()
19276                {
19277                    continue;
19278                }
19279                let snapshot = self.buffer.read(cx).snapshot(cx);
19280                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19281
19282                handled = true;
19283                self.clear_row_highlights::<ActiveDebugLine>();
19284
19285                self.go_to_line::<ActiveDebugLine>(
19286                    multibuffer_anchor,
19287                    Some(cx.theme().colors().editor_debugger_active_line_background),
19288                    window,
19289                    cx,
19290                );
19291
19292                cx.notify();
19293            }
19294
19295            handled.then_some(())
19296        })
19297        .is_some()
19298    }
19299
19300    pub fn copy_file_name_without_extension(
19301        &mut self,
19302        _: &CopyFileNameWithoutExtension,
19303        _: &mut Window,
19304        cx: &mut Context<Self>,
19305    ) {
19306        if let Some(file) = self.target_file(cx)
19307            && let Some(file_stem) = file.path().file_stem()
19308            && let Some(name) = file_stem.to_str()
19309        {
19310            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19311        }
19312    }
19313
19314    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19315        if let Some(file) = self.target_file(cx)
19316            && let Some(file_name) = file.path().file_name()
19317            && let Some(name) = file_name.to_str()
19318        {
19319            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19320        }
19321    }
19322
19323    pub fn toggle_git_blame(
19324        &mut self,
19325        _: &::git::Blame,
19326        window: &mut Window,
19327        cx: &mut Context<Self>,
19328    ) {
19329        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19330
19331        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19332            self.start_git_blame(true, window, cx);
19333        }
19334
19335        cx.notify();
19336    }
19337
19338    pub fn toggle_git_blame_inline(
19339        &mut self,
19340        _: &ToggleGitBlameInline,
19341        window: &mut Window,
19342        cx: &mut Context<Self>,
19343    ) {
19344        self.toggle_git_blame_inline_internal(true, window, cx);
19345        cx.notify();
19346    }
19347
19348    pub fn open_git_blame_commit(
19349        &mut self,
19350        _: &OpenGitBlameCommit,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        self.open_git_blame_commit_internal(window, cx);
19355    }
19356
19357    fn open_git_blame_commit_internal(
19358        &mut self,
19359        window: &mut Window,
19360        cx: &mut Context<Self>,
19361    ) -> Option<()> {
19362        let blame = self.blame.as_ref()?;
19363        let snapshot = self.snapshot(window, cx);
19364        let cursor = self.selections.newest::<Point>(cx).head();
19365        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19366        let (_, blame_entry) = blame
19367            .update(cx, |blame, cx| {
19368                blame
19369                    .blame_for_rows(
19370                        &[RowInfo {
19371                            buffer_id: Some(buffer.remote_id()),
19372                            buffer_row: Some(point.row),
19373                            ..Default::default()
19374                        }],
19375                        cx,
19376                    )
19377                    .next()
19378            })
19379            .flatten()?;
19380        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19381        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19382        let workspace = self.workspace()?.downgrade();
19383        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19384        None
19385    }
19386
19387    pub fn git_blame_inline_enabled(&self) -> bool {
19388        self.git_blame_inline_enabled
19389    }
19390
19391    pub fn toggle_selection_menu(
19392        &mut self,
19393        _: &ToggleSelectionMenu,
19394        _: &mut Window,
19395        cx: &mut Context<Self>,
19396    ) {
19397        self.show_selection_menu = self
19398            .show_selection_menu
19399            .map(|show_selections_menu| !show_selections_menu)
19400            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19401
19402        cx.notify();
19403    }
19404
19405    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19406        self.show_selection_menu
19407            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19408    }
19409
19410    fn start_git_blame(
19411        &mut self,
19412        user_triggered: bool,
19413        window: &mut Window,
19414        cx: &mut Context<Self>,
19415    ) {
19416        if let Some(project) = self.project() {
19417            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19418                && buffer.read(cx).file().is_none()
19419            {
19420                return;
19421            }
19422
19423            let focused = self.focus_handle(cx).contains_focused(window, cx);
19424
19425            let project = project.clone();
19426            let blame = cx
19427                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19428            self.blame_subscription =
19429                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19430            self.blame = Some(blame);
19431        }
19432    }
19433
19434    fn toggle_git_blame_inline_internal(
19435        &mut self,
19436        user_triggered: bool,
19437        window: &mut Window,
19438        cx: &mut Context<Self>,
19439    ) {
19440        if self.git_blame_inline_enabled {
19441            self.git_blame_inline_enabled = false;
19442            self.show_git_blame_inline = false;
19443            self.show_git_blame_inline_delay_task.take();
19444        } else {
19445            self.git_blame_inline_enabled = true;
19446            self.start_git_blame_inline(user_triggered, window, cx);
19447        }
19448
19449        cx.notify();
19450    }
19451
19452    fn start_git_blame_inline(
19453        &mut self,
19454        user_triggered: bool,
19455        window: &mut Window,
19456        cx: &mut Context<Self>,
19457    ) {
19458        self.start_git_blame(user_triggered, window, cx);
19459
19460        if ProjectSettings::get_global(cx)
19461            .git
19462            .inline_blame_delay()
19463            .is_some()
19464        {
19465            self.start_inline_blame_timer(window, cx);
19466        } else {
19467            self.show_git_blame_inline = true
19468        }
19469    }
19470
19471    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19472        self.blame.as_ref()
19473    }
19474
19475    pub fn show_git_blame_gutter(&self) -> bool {
19476        self.show_git_blame_gutter
19477    }
19478
19479    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19480        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19481    }
19482
19483    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19484        self.show_git_blame_inline
19485            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19486            && !self.newest_selection_head_on_empty_line(cx)
19487            && self.has_blame_entries(cx)
19488    }
19489
19490    fn has_blame_entries(&self, cx: &App) -> bool {
19491        self.blame()
19492            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19493    }
19494
19495    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19496        let cursor_anchor = self.selections.newest_anchor().head();
19497
19498        let snapshot = self.buffer.read(cx).snapshot(cx);
19499        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19500
19501        snapshot.line_len(buffer_row) == 0
19502    }
19503
19504    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19505        let buffer_and_selection = maybe!({
19506            let selection = self.selections.newest::<Point>(cx);
19507            let selection_range = selection.range();
19508
19509            let multi_buffer = self.buffer().read(cx);
19510            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19511            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19512
19513            let (buffer, range, _) = if selection.reversed {
19514                buffer_ranges.first()
19515            } else {
19516                buffer_ranges.last()
19517            }?;
19518
19519            let selection = text::ToPoint::to_point(&range.start, buffer).row
19520                ..text::ToPoint::to_point(&range.end, buffer).row;
19521            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19522        });
19523
19524        let Some((buffer, selection)) = buffer_and_selection else {
19525            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19526        };
19527
19528        let Some(project) = self.project() else {
19529            return Task::ready(Err(anyhow!("editor does not have project")));
19530        };
19531
19532        project.update(cx, |project, cx| {
19533            project.get_permalink_to_line(&buffer, selection, cx)
19534        })
19535    }
19536
19537    pub fn copy_permalink_to_line(
19538        &mut self,
19539        _: &CopyPermalinkToLine,
19540        window: &mut Window,
19541        cx: &mut Context<Self>,
19542    ) {
19543        let permalink_task = self.get_permalink_to_line(cx);
19544        let workspace = self.workspace();
19545
19546        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19547            Ok(permalink) => {
19548                cx.update(|_, cx| {
19549                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19550                })
19551                .ok();
19552            }
19553            Err(err) => {
19554                let message = format!("Failed to copy permalink: {err}");
19555
19556                anyhow::Result::<()>::Err(err).log_err();
19557
19558                if let Some(workspace) = workspace {
19559                    workspace
19560                        .update_in(cx, |workspace, _, cx| {
19561                            struct CopyPermalinkToLine;
19562
19563                            workspace.show_toast(
19564                                Toast::new(
19565                                    NotificationId::unique::<CopyPermalinkToLine>(),
19566                                    message,
19567                                ),
19568                                cx,
19569                            )
19570                        })
19571                        .ok();
19572                }
19573            }
19574        })
19575        .detach();
19576    }
19577
19578    pub fn copy_file_location(
19579        &mut self,
19580        _: &CopyFileLocation,
19581        _: &mut Window,
19582        cx: &mut Context<Self>,
19583    ) {
19584        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19585        if let Some(file) = self.target_file(cx)
19586            && let Some(path) = file.path().to_str()
19587        {
19588            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19589        }
19590    }
19591
19592    pub fn open_permalink_to_line(
19593        &mut self,
19594        _: &OpenPermalinkToLine,
19595        window: &mut Window,
19596        cx: &mut Context<Self>,
19597    ) {
19598        let permalink_task = self.get_permalink_to_line(cx);
19599        let workspace = self.workspace();
19600
19601        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19602            Ok(permalink) => {
19603                cx.update(|_, cx| {
19604                    cx.open_url(permalink.as_ref());
19605                })
19606                .ok();
19607            }
19608            Err(err) => {
19609                let message = format!("Failed to open permalink: {err}");
19610
19611                anyhow::Result::<()>::Err(err).log_err();
19612
19613                if let Some(workspace) = workspace {
19614                    workspace
19615                        .update(cx, |workspace, cx| {
19616                            struct OpenPermalinkToLine;
19617
19618                            workspace.show_toast(
19619                                Toast::new(
19620                                    NotificationId::unique::<OpenPermalinkToLine>(),
19621                                    message,
19622                                ),
19623                                cx,
19624                            )
19625                        })
19626                        .ok();
19627                }
19628            }
19629        })
19630        .detach();
19631    }
19632
19633    pub fn insert_uuid_v4(
19634        &mut self,
19635        _: &InsertUuidV4,
19636        window: &mut Window,
19637        cx: &mut Context<Self>,
19638    ) {
19639        self.insert_uuid(UuidVersion::V4, window, cx);
19640    }
19641
19642    pub fn insert_uuid_v7(
19643        &mut self,
19644        _: &InsertUuidV7,
19645        window: &mut Window,
19646        cx: &mut Context<Self>,
19647    ) {
19648        self.insert_uuid(UuidVersion::V7, window, cx);
19649    }
19650
19651    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19653        self.transact(window, cx, |this, window, cx| {
19654            let edits = this
19655                .selections
19656                .all::<Point>(cx)
19657                .into_iter()
19658                .map(|selection| {
19659                    let uuid = match version {
19660                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19661                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19662                    };
19663
19664                    (selection.range(), uuid.to_string())
19665                });
19666            this.edit(edits, cx);
19667            this.refresh_edit_prediction(true, false, window, cx);
19668        });
19669    }
19670
19671    pub fn open_selections_in_multibuffer(
19672        &mut self,
19673        _: &OpenSelectionsInMultibuffer,
19674        window: &mut Window,
19675        cx: &mut Context<Self>,
19676    ) {
19677        let multibuffer = self.buffer.read(cx);
19678
19679        let Some(buffer) = multibuffer.as_singleton() else {
19680            return;
19681        };
19682
19683        let Some(workspace) = self.workspace() else {
19684            return;
19685        };
19686
19687        let title = multibuffer.title(cx).to_string();
19688
19689        let locations = self
19690            .selections
19691            .all_anchors(cx)
19692            .iter()
19693            .map(|selection| Location {
19694                buffer: buffer.clone(),
19695                range: selection.start.text_anchor..selection.end.text_anchor,
19696            })
19697            .collect::<Vec<_>>();
19698
19699        cx.spawn_in(window, async move |_, cx| {
19700            workspace.update_in(cx, |workspace, window, cx| {
19701                Self::open_locations_in_multibuffer(
19702                    workspace,
19703                    locations,
19704                    format!("Selections for '{title}'"),
19705                    false,
19706                    MultibufferSelectionMode::All,
19707                    window,
19708                    cx,
19709                );
19710            })
19711        })
19712        .detach();
19713    }
19714
19715    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19716    /// last highlight added will be used.
19717    ///
19718    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19719    pub fn highlight_rows<T: 'static>(
19720        &mut self,
19721        range: Range<Anchor>,
19722        color: Hsla,
19723        options: RowHighlightOptions,
19724        cx: &mut Context<Self>,
19725    ) {
19726        let snapshot = self.buffer().read(cx).snapshot(cx);
19727        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19728        let ix = row_highlights.binary_search_by(|highlight| {
19729            Ordering::Equal
19730                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19731                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19732        });
19733
19734        if let Err(mut ix) = ix {
19735            let index = post_inc(&mut self.highlight_order);
19736
19737            // If this range intersects with the preceding highlight, then merge it with
19738            // the preceding highlight. Otherwise insert a new highlight.
19739            let mut merged = false;
19740            if ix > 0 {
19741                let prev_highlight = &mut row_highlights[ix - 1];
19742                if prev_highlight
19743                    .range
19744                    .end
19745                    .cmp(&range.start, &snapshot)
19746                    .is_ge()
19747                {
19748                    ix -= 1;
19749                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19750                        prev_highlight.range.end = range.end;
19751                    }
19752                    merged = true;
19753                    prev_highlight.index = index;
19754                    prev_highlight.color = color;
19755                    prev_highlight.options = options;
19756                }
19757            }
19758
19759            if !merged {
19760                row_highlights.insert(
19761                    ix,
19762                    RowHighlight {
19763                        range,
19764                        index,
19765                        color,
19766                        options,
19767                        type_id: TypeId::of::<T>(),
19768                    },
19769                );
19770            }
19771
19772            // If any of the following highlights intersect with this one, merge them.
19773            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19774                let highlight = &row_highlights[ix];
19775                if next_highlight
19776                    .range
19777                    .start
19778                    .cmp(&highlight.range.end, &snapshot)
19779                    .is_le()
19780                {
19781                    if next_highlight
19782                        .range
19783                        .end
19784                        .cmp(&highlight.range.end, &snapshot)
19785                        .is_gt()
19786                    {
19787                        row_highlights[ix].range.end = next_highlight.range.end;
19788                    }
19789                    row_highlights.remove(ix + 1);
19790                } else {
19791                    break;
19792                }
19793            }
19794        }
19795    }
19796
19797    /// Remove any highlighted row ranges of the given type that intersect the
19798    /// given ranges.
19799    pub fn remove_highlighted_rows<T: 'static>(
19800        &mut self,
19801        ranges_to_remove: Vec<Range<Anchor>>,
19802        cx: &mut Context<Self>,
19803    ) {
19804        let snapshot = self.buffer().read(cx).snapshot(cx);
19805        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19806        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19807        row_highlights.retain(|highlight| {
19808            while let Some(range_to_remove) = ranges_to_remove.peek() {
19809                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19810                    Ordering::Less | Ordering::Equal => {
19811                        ranges_to_remove.next();
19812                    }
19813                    Ordering::Greater => {
19814                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19815                            Ordering::Less | Ordering::Equal => {
19816                                return false;
19817                            }
19818                            Ordering::Greater => break,
19819                        }
19820                    }
19821                }
19822            }
19823
19824            true
19825        })
19826    }
19827
19828    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19829    pub fn clear_row_highlights<T: 'static>(&mut self) {
19830        self.highlighted_rows.remove(&TypeId::of::<T>());
19831    }
19832
19833    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19834    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19835        self.highlighted_rows
19836            .get(&TypeId::of::<T>())
19837            .map_or(&[] as &[_], |vec| vec.as_slice())
19838            .iter()
19839            .map(|highlight| (highlight.range.clone(), highlight.color))
19840    }
19841
19842    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19843    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19844    /// Allows to ignore certain kinds of highlights.
19845    pub fn highlighted_display_rows(
19846        &self,
19847        window: &mut Window,
19848        cx: &mut App,
19849    ) -> BTreeMap<DisplayRow, LineHighlight> {
19850        let snapshot = self.snapshot(window, cx);
19851        let mut used_highlight_orders = HashMap::default();
19852        self.highlighted_rows
19853            .iter()
19854            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19855            .fold(
19856                BTreeMap::<DisplayRow, LineHighlight>::new(),
19857                |mut unique_rows, highlight| {
19858                    let start = highlight.range.start.to_display_point(&snapshot);
19859                    let end = highlight.range.end.to_display_point(&snapshot);
19860                    let start_row = start.row().0;
19861                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19862                        && end.column() == 0
19863                    {
19864                        end.row().0.saturating_sub(1)
19865                    } else {
19866                        end.row().0
19867                    };
19868                    for row in start_row..=end_row {
19869                        let used_index =
19870                            used_highlight_orders.entry(row).or_insert(highlight.index);
19871                        if highlight.index >= *used_index {
19872                            *used_index = highlight.index;
19873                            unique_rows.insert(
19874                                DisplayRow(row),
19875                                LineHighlight {
19876                                    include_gutter: highlight.options.include_gutter,
19877                                    border: None,
19878                                    background: highlight.color.into(),
19879                                    type_id: Some(highlight.type_id),
19880                                },
19881                            );
19882                        }
19883                    }
19884                    unique_rows
19885                },
19886            )
19887    }
19888
19889    pub fn highlighted_display_row_for_autoscroll(
19890        &self,
19891        snapshot: &DisplaySnapshot,
19892    ) -> Option<DisplayRow> {
19893        self.highlighted_rows
19894            .values()
19895            .flat_map(|highlighted_rows| highlighted_rows.iter())
19896            .filter_map(|highlight| {
19897                if highlight.options.autoscroll {
19898                    Some(highlight.range.start.to_display_point(snapshot).row())
19899                } else {
19900                    None
19901                }
19902            })
19903            .min()
19904    }
19905
19906    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19907        self.highlight_background::<SearchWithinRange>(
19908            ranges,
19909            |colors| colors.colors().editor_document_highlight_read_background,
19910            cx,
19911        )
19912    }
19913
19914    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19915        self.breadcrumb_header = Some(new_header);
19916    }
19917
19918    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19919        self.clear_background_highlights::<SearchWithinRange>(cx);
19920    }
19921
19922    pub fn highlight_background<T: 'static>(
19923        &mut self,
19924        ranges: &[Range<Anchor>],
19925        color_fetcher: fn(&Theme) -> Hsla,
19926        cx: &mut Context<Self>,
19927    ) {
19928        self.background_highlights.insert(
19929            HighlightKey::Type(TypeId::of::<T>()),
19930            (color_fetcher, Arc::from(ranges)),
19931        );
19932        self.scrollbar_marker_state.dirty = true;
19933        cx.notify();
19934    }
19935
19936    pub fn highlight_background_key<T: 'static>(
19937        &mut self,
19938        key: usize,
19939        ranges: &[Range<Anchor>],
19940        color_fetcher: fn(&Theme) -> Hsla,
19941        cx: &mut Context<Self>,
19942    ) {
19943        self.background_highlights.insert(
19944            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19945            (color_fetcher, Arc::from(ranges)),
19946        );
19947        self.scrollbar_marker_state.dirty = true;
19948        cx.notify();
19949    }
19950
19951    pub fn clear_background_highlights<T: 'static>(
19952        &mut self,
19953        cx: &mut Context<Self>,
19954    ) -> Option<BackgroundHighlight> {
19955        let text_highlights = self
19956            .background_highlights
19957            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19958        if !text_highlights.1.is_empty() {
19959            self.scrollbar_marker_state.dirty = true;
19960            cx.notify();
19961        }
19962        Some(text_highlights)
19963    }
19964
19965    pub fn highlight_gutter<T: 'static>(
19966        &mut self,
19967        ranges: impl Into<Vec<Range<Anchor>>>,
19968        color_fetcher: fn(&App) -> Hsla,
19969        cx: &mut Context<Self>,
19970    ) {
19971        self.gutter_highlights
19972            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19973        cx.notify();
19974    }
19975
19976    pub fn clear_gutter_highlights<T: 'static>(
19977        &mut self,
19978        cx: &mut Context<Self>,
19979    ) -> Option<GutterHighlight> {
19980        cx.notify();
19981        self.gutter_highlights.remove(&TypeId::of::<T>())
19982    }
19983
19984    pub fn insert_gutter_highlight<T: 'static>(
19985        &mut self,
19986        range: Range<Anchor>,
19987        color_fetcher: fn(&App) -> Hsla,
19988        cx: &mut Context<Self>,
19989    ) {
19990        let snapshot = self.buffer().read(cx).snapshot(cx);
19991        let mut highlights = self
19992            .gutter_highlights
19993            .remove(&TypeId::of::<T>())
19994            .map(|(_, highlights)| highlights)
19995            .unwrap_or_default();
19996        let ix = highlights.binary_search_by(|highlight| {
19997            Ordering::Equal
19998                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19999                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20000        });
20001        if let Err(ix) = ix {
20002            highlights.insert(ix, range);
20003        }
20004        self.gutter_highlights
20005            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20006    }
20007
20008    pub fn remove_gutter_highlights<T: 'static>(
20009        &mut self,
20010        ranges_to_remove: Vec<Range<Anchor>>,
20011        cx: &mut Context<Self>,
20012    ) {
20013        let snapshot = self.buffer().read(cx).snapshot(cx);
20014        let Some((color_fetcher, mut gutter_highlights)) =
20015            self.gutter_highlights.remove(&TypeId::of::<T>())
20016        else {
20017            return;
20018        };
20019        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20020        gutter_highlights.retain(|highlight| {
20021            while let Some(range_to_remove) = ranges_to_remove.peek() {
20022                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20023                    Ordering::Less | Ordering::Equal => {
20024                        ranges_to_remove.next();
20025                    }
20026                    Ordering::Greater => {
20027                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20028                            Ordering::Less | Ordering::Equal => {
20029                                return false;
20030                            }
20031                            Ordering::Greater => break,
20032                        }
20033                    }
20034                }
20035            }
20036
20037            true
20038        });
20039        self.gutter_highlights
20040            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20041    }
20042
20043    #[cfg(feature = "test-support")]
20044    pub fn all_text_highlights(
20045        &self,
20046        window: &mut Window,
20047        cx: &mut Context<Self>,
20048    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20049        let snapshot = self.snapshot(window, cx);
20050        self.display_map.update(cx, |display_map, _| {
20051            display_map
20052                .all_text_highlights()
20053                .map(|highlight| {
20054                    let (style, ranges) = highlight.as_ref();
20055                    (
20056                        *style,
20057                        ranges
20058                            .iter()
20059                            .map(|range| range.clone().to_display_points(&snapshot))
20060                            .collect(),
20061                    )
20062                })
20063                .collect()
20064        })
20065    }
20066
20067    #[cfg(feature = "test-support")]
20068    pub fn all_text_background_highlights(
20069        &self,
20070        window: &mut Window,
20071        cx: &mut Context<Self>,
20072    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20073        let snapshot = self.snapshot(window, cx);
20074        let buffer = &snapshot.buffer_snapshot;
20075        let start = buffer.anchor_before(0);
20076        let end = buffer.anchor_after(buffer.len());
20077        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20078    }
20079
20080    #[cfg(any(test, feature = "test-support"))]
20081    pub fn sorted_background_highlights_in_range(
20082        &self,
20083        search_range: Range<Anchor>,
20084        display_snapshot: &DisplaySnapshot,
20085        theme: &Theme,
20086    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20087        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20088        res.sort_by(|a, b| {
20089            a.0.start
20090                .cmp(&b.0.start)
20091                .then_with(|| a.0.end.cmp(&b.0.end))
20092                .then_with(|| a.1.cmp(&b.1))
20093        });
20094        res
20095    }
20096
20097    #[cfg(feature = "test-support")]
20098    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20099        let snapshot = self.buffer().read(cx).snapshot(cx);
20100
20101        let highlights = self
20102            .background_highlights
20103            .get(&HighlightKey::Type(TypeId::of::<
20104                items::BufferSearchHighlights,
20105            >()));
20106
20107        if let Some((_color, ranges)) = highlights {
20108            ranges
20109                .iter()
20110                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20111                .collect_vec()
20112        } else {
20113            vec![]
20114        }
20115    }
20116
20117    fn document_highlights_for_position<'a>(
20118        &'a self,
20119        position: Anchor,
20120        buffer: &'a MultiBufferSnapshot,
20121    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20122        let read_highlights = self
20123            .background_highlights
20124            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20125            .map(|h| &h.1);
20126        let write_highlights = self
20127            .background_highlights
20128            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20129            .map(|h| &h.1);
20130        let left_position = position.bias_left(buffer);
20131        let right_position = position.bias_right(buffer);
20132        read_highlights
20133            .into_iter()
20134            .chain(write_highlights)
20135            .flat_map(move |ranges| {
20136                let start_ix = match ranges.binary_search_by(|probe| {
20137                    let cmp = probe.end.cmp(&left_position, buffer);
20138                    if cmp.is_ge() {
20139                        Ordering::Greater
20140                    } else {
20141                        Ordering::Less
20142                    }
20143                }) {
20144                    Ok(i) | Err(i) => i,
20145                };
20146
20147                ranges[start_ix..]
20148                    .iter()
20149                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20150            })
20151    }
20152
20153    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20154        self.background_highlights
20155            .get(&HighlightKey::Type(TypeId::of::<T>()))
20156            .is_some_and(|(_, highlights)| !highlights.is_empty())
20157    }
20158
20159    /// Returns all background highlights for a given range.
20160    ///
20161    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20162    pub fn background_highlights_in_range(
20163        &self,
20164        search_range: Range<Anchor>,
20165        display_snapshot: &DisplaySnapshot,
20166        theme: &Theme,
20167    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20168        let mut results = Vec::new();
20169        for (color_fetcher, ranges) in self.background_highlights.values() {
20170            let color = color_fetcher(theme);
20171            let start_ix = match ranges.binary_search_by(|probe| {
20172                let cmp = probe
20173                    .end
20174                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20175                if cmp.is_gt() {
20176                    Ordering::Greater
20177                } else {
20178                    Ordering::Less
20179                }
20180            }) {
20181                Ok(i) | Err(i) => i,
20182            };
20183            for range in &ranges[start_ix..] {
20184                if range
20185                    .start
20186                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20187                    .is_ge()
20188                {
20189                    break;
20190                }
20191
20192                let start = range.start.to_display_point(display_snapshot);
20193                let end = range.end.to_display_point(display_snapshot);
20194                results.push((start..end, color))
20195            }
20196        }
20197        results
20198    }
20199
20200    pub fn gutter_highlights_in_range(
20201        &self,
20202        search_range: Range<Anchor>,
20203        display_snapshot: &DisplaySnapshot,
20204        cx: &App,
20205    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20206        let mut results = Vec::new();
20207        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20208            let color = color_fetcher(cx);
20209            let start_ix = match ranges.binary_search_by(|probe| {
20210                let cmp = probe
20211                    .end
20212                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20213                if cmp.is_gt() {
20214                    Ordering::Greater
20215                } else {
20216                    Ordering::Less
20217                }
20218            }) {
20219                Ok(i) | Err(i) => i,
20220            };
20221            for range in &ranges[start_ix..] {
20222                if range
20223                    .start
20224                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20225                    .is_ge()
20226                {
20227                    break;
20228                }
20229
20230                let start = range.start.to_display_point(display_snapshot);
20231                let end = range.end.to_display_point(display_snapshot);
20232                results.push((start..end, color))
20233            }
20234        }
20235        results
20236    }
20237
20238    /// Get the text ranges corresponding to the redaction query
20239    pub fn redacted_ranges(
20240        &self,
20241        search_range: Range<Anchor>,
20242        display_snapshot: &DisplaySnapshot,
20243        cx: &App,
20244    ) -> Vec<Range<DisplayPoint>> {
20245        display_snapshot
20246            .buffer_snapshot
20247            .redacted_ranges(search_range, |file| {
20248                if let Some(file) = file {
20249                    file.is_private()
20250                        && EditorSettings::get(
20251                            Some(SettingsLocation {
20252                                worktree_id: file.worktree_id(cx),
20253                                path: file.path().as_ref(),
20254                            }),
20255                            cx,
20256                        )
20257                        .redact_private_values
20258                } else {
20259                    false
20260                }
20261            })
20262            .map(|range| {
20263                range.start.to_display_point(display_snapshot)
20264                    ..range.end.to_display_point(display_snapshot)
20265            })
20266            .collect()
20267    }
20268
20269    pub fn highlight_text_key<T: 'static>(
20270        &mut self,
20271        key: usize,
20272        ranges: Vec<Range<Anchor>>,
20273        style: HighlightStyle,
20274        cx: &mut Context<Self>,
20275    ) {
20276        self.display_map.update(cx, |map, _| {
20277            map.highlight_text(
20278                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20279                ranges,
20280                style,
20281            );
20282        });
20283        cx.notify();
20284    }
20285
20286    pub fn highlight_text<T: 'static>(
20287        &mut self,
20288        ranges: Vec<Range<Anchor>>,
20289        style: HighlightStyle,
20290        cx: &mut Context<Self>,
20291    ) {
20292        self.display_map.update(cx, |map, _| {
20293            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20294        });
20295        cx.notify();
20296    }
20297
20298    pub(crate) fn highlight_inlays<T: 'static>(
20299        &mut self,
20300        highlights: Vec<InlayHighlight>,
20301        style: HighlightStyle,
20302        cx: &mut Context<Self>,
20303    ) {
20304        self.display_map.update(cx, |map, _| {
20305            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20306        });
20307        cx.notify();
20308    }
20309
20310    pub fn text_highlights<'a, T: 'static>(
20311        &'a self,
20312        cx: &'a App,
20313    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20314        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20315    }
20316
20317    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20318        let cleared = self
20319            .display_map
20320            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20321        if cleared {
20322            cx.notify();
20323        }
20324    }
20325
20326    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20327        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20328            && self.focus_handle.is_focused(window)
20329    }
20330
20331    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20332        self.show_cursor_when_unfocused = is_enabled;
20333        cx.notify();
20334    }
20335
20336    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20337        cx.notify();
20338    }
20339
20340    fn on_debug_session_event(
20341        &mut self,
20342        _session: Entity<Session>,
20343        event: &SessionEvent,
20344        cx: &mut Context<Self>,
20345    ) {
20346        if let SessionEvent::InvalidateInlineValue = event {
20347            self.refresh_inline_values(cx);
20348        }
20349    }
20350
20351    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20352        let Some(project) = self.project.clone() else {
20353            return;
20354        };
20355
20356        if !self.inline_value_cache.enabled {
20357            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20358            self.splice_inlays(&inlays, Vec::new(), cx);
20359            return;
20360        }
20361
20362        let current_execution_position = self
20363            .highlighted_rows
20364            .get(&TypeId::of::<ActiveDebugLine>())
20365            .and_then(|lines| lines.last().map(|line| line.range.end));
20366
20367        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20368            let inline_values = editor
20369                .update(cx, |editor, cx| {
20370                    let Some(current_execution_position) = current_execution_position else {
20371                        return Some(Task::ready(Ok(Vec::new())));
20372                    };
20373
20374                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20375                        let snapshot = buffer.snapshot(cx);
20376
20377                        let excerpt = snapshot.excerpt_containing(
20378                            current_execution_position..current_execution_position,
20379                        )?;
20380
20381                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20382                    })?;
20383
20384                    let range =
20385                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20386
20387                    project.inline_values(buffer, range, cx)
20388                })
20389                .ok()
20390                .flatten()?
20391                .await
20392                .context("refreshing debugger inlays")
20393                .log_err()?;
20394
20395            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20396
20397            for (buffer_id, inline_value) in inline_values
20398                .into_iter()
20399                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20400            {
20401                buffer_inline_values
20402                    .entry(buffer_id)
20403                    .or_default()
20404                    .push(inline_value);
20405            }
20406
20407            editor
20408                .update(cx, |editor, cx| {
20409                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20410                    let mut new_inlays = Vec::default();
20411
20412                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20413                        let buffer_id = buffer_snapshot.remote_id();
20414                        buffer_inline_values
20415                            .get(&buffer_id)
20416                            .into_iter()
20417                            .flatten()
20418                            .for_each(|hint| {
20419                                let inlay = Inlay::debugger(
20420                                    post_inc(&mut editor.next_inlay_id),
20421                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20422                                    hint.text(),
20423                                );
20424                                if !inlay.text.chars().contains(&'\n') {
20425                                    new_inlays.push(inlay);
20426                                }
20427                            });
20428                    }
20429
20430                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20431                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20432
20433                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20434                })
20435                .ok()?;
20436            Some(())
20437        });
20438    }
20439
20440    fn on_buffer_event(
20441        &mut self,
20442        multibuffer: &Entity<MultiBuffer>,
20443        event: &multi_buffer::Event,
20444        window: &mut Window,
20445        cx: &mut Context<Self>,
20446    ) {
20447        match event {
20448            multi_buffer::Event::Edited {
20449                singleton_buffer_edited,
20450                edited_buffer,
20451            } => {
20452                self.scrollbar_marker_state.dirty = true;
20453                self.active_indent_guides_state.dirty = true;
20454                self.refresh_active_diagnostics(cx);
20455                self.refresh_code_actions(window, cx);
20456                self.refresh_selected_text_highlights(true, window, cx);
20457                self.refresh_single_line_folds(window, cx);
20458                refresh_matching_bracket_highlights(self, window, cx);
20459                if self.has_active_edit_prediction() {
20460                    self.update_visible_edit_prediction(window, cx);
20461                }
20462                if let Some(project) = self.project.as_ref()
20463                    && let Some(edited_buffer) = edited_buffer
20464                {
20465                    project.update(cx, |project, cx| {
20466                        self.registered_buffers
20467                            .entry(edited_buffer.read(cx).remote_id())
20468                            .or_insert_with(|| {
20469                                project.register_buffer_with_language_servers(edited_buffer, cx)
20470                            });
20471                    });
20472                }
20473                cx.emit(EditorEvent::BufferEdited);
20474                cx.emit(SearchEvent::MatchesInvalidated);
20475
20476                if let Some(buffer) = edited_buffer {
20477                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20478                }
20479
20480                if *singleton_buffer_edited {
20481                    if let Some(buffer) = edited_buffer
20482                        && buffer.read(cx).file().is_none()
20483                    {
20484                        cx.emit(EditorEvent::TitleChanged);
20485                    }
20486                    if let Some(project) = &self.project {
20487                        #[allow(clippy::mutable_key_type)]
20488                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20489                            multibuffer
20490                                .all_buffers()
20491                                .into_iter()
20492                                .filter_map(|buffer| {
20493                                    buffer.update(cx, |buffer, cx| {
20494                                        let language = buffer.language()?;
20495                                        let should_discard = project.update(cx, |project, cx| {
20496                                            project.is_local()
20497                                                && !project.has_language_servers_for(buffer, cx)
20498                                        });
20499                                        should_discard.not().then_some(language.clone())
20500                                    })
20501                                })
20502                                .collect::<HashSet<_>>()
20503                        });
20504                        if !languages_affected.is_empty() {
20505                            self.refresh_inlay_hints(
20506                                InlayHintRefreshReason::BufferEdited(languages_affected),
20507                                cx,
20508                            );
20509                        }
20510                    }
20511                }
20512
20513                let Some(project) = &self.project else { return };
20514                let (telemetry, is_via_ssh) = {
20515                    let project = project.read(cx);
20516                    let telemetry = project.client().telemetry().clone();
20517                    let is_via_ssh = project.is_via_remote_server();
20518                    (telemetry, is_via_ssh)
20519                };
20520                refresh_linked_ranges(self, window, cx);
20521                telemetry.log_edit_event("editor", is_via_ssh);
20522            }
20523            multi_buffer::Event::ExcerptsAdded {
20524                buffer,
20525                predecessor,
20526                excerpts,
20527            } => {
20528                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20529                let buffer_id = buffer.read(cx).remote_id();
20530                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20531                    && let Some(project) = &self.project
20532                {
20533                    update_uncommitted_diff_for_buffer(
20534                        cx.entity(),
20535                        project,
20536                        [buffer.clone()],
20537                        self.buffer.clone(),
20538                        cx,
20539                    )
20540                    .detach();
20541                }
20542                if self.active_diagnostics != ActiveDiagnostic::All {
20543                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20544                }
20545                cx.emit(EditorEvent::ExcerptsAdded {
20546                    buffer: buffer.clone(),
20547                    predecessor: *predecessor,
20548                    excerpts: excerpts.clone(),
20549                });
20550                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20551            }
20552            multi_buffer::Event::ExcerptsRemoved {
20553                ids,
20554                removed_buffer_ids,
20555            } => {
20556                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20557                let buffer = self.buffer.read(cx);
20558                self.registered_buffers
20559                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20560                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20561                cx.emit(EditorEvent::ExcerptsRemoved {
20562                    ids: ids.clone(),
20563                    removed_buffer_ids: removed_buffer_ids.clone(),
20564                });
20565            }
20566            multi_buffer::Event::ExcerptsEdited {
20567                excerpt_ids,
20568                buffer_ids,
20569            } => {
20570                self.display_map.update(cx, |map, cx| {
20571                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20572                });
20573                cx.emit(EditorEvent::ExcerptsEdited {
20574                    ids: excerpt_ids.clone(),
20575                });
20576            }
20577            multi_buffer::Event::ExcerptsExpanded { ids } => {
20578                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20579                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20580            }
20581            multi_buffer::Event::Reparsed(buffer_id) => {
20582                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20583                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20584
20585                cx.emit(EditorEvent::Reparsed(*buffer_id));
20586            }
20587            multi_buffer::Event::DiffHunksToggled => {
20588                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20589            }
20590            multi_buffer::Event::LanguageChanged(buffer_id) => {
20591                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20592                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20593                cx.emit(EditorEvent::Reparsed(*buffer_id));
20594                cx.notify();
20595            }
20596            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20597            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20598            multi_buffer::Event::FileHandleChanged
20599            | multi_buffer::Event::Reloaded
20600            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20601            multi_buffer::Event::DiagnosticsUpdated => {
20602                self.update_diagnostics_state(window, cx);
20603            }
20604            _ => {}
20605        };
20606    }
20607
20608    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20609        if !self.diagnostics_enabled() {
20610            return;
20611        }
20612        self.refresh_active_diagnostics(cx);
20613        self.refresh_inline_diagnostics(true, window, cx);
20614        self.scrollbar_marker_state.dirty = true;
20615        cx.notify();
20616    }
20617
20618    pub fn start_temporary_diff_override(&mut self) {
20619        self.load_diff_task.take();
20620        self.temporary_diff_override = true;
20621    }
20622
20623    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20624        self.temporary_diff_override = false;
20625        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20626        self.buffer.update(cx, |buffer, cx| {
20627            buffer.set_all_diff_hunks_collapsed(cx);
20628        });
20629
20630        if let Some(project) = self.project.clone() {
20631            self.load_diff_task = Some(
20632                update_uncommitted_diff_for_buffer(
20633                    cx.entity(),
20634                    &project,
20635                    self.buffer.read(cx).all_buffers(),
20636                    self.buffer.clone(),
20637                    cx,
20638                )
20639                .shared(),
20640            );
20641        }
20642    }
20643
20644    fn on_display_map_changed(
20645        &mut self,
20646        _: Entity<DisplayMap>,
20647        _: &mut Window,
20648        cx: &mut Context<Self>,
20649    ) {
20650        cx.notify();
20651    }
20652
20653    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20654        if self.diagnostics_enabled() {
20655            let new_severity = EditorSettings::get_global(cx)
20656                .diagnostics_max_severity
20657                .unwrap_or(DiagnosticSeverity::Hint);
20658            self.set_max_diagnostics_severity(new_severity, cx);
20659        }
20660        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20661        self.update_edit_prediction_settings(cx);
20662        self.refresh_edit_prediction(true, false, window, cx);
20663        self.refresh_inline_values(cx);
20664        self.refresh_inlay_hints(
20665            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20666                self.selections.newest_anchor().head(),
20667                &self.buffer.read(cx).snapshot(cx),
20668                cx,
20669            )),
20670            cx,
20671        );
20672
20673        let old_cursor_shape = self.cursor_shape;
20674        let old_show_breadcrumbs = self.show_breadcrumbs;
20675
20676        {
20677            let editor_settings = EditorSettings::get_global(cx);
20678            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20679            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20680            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20681            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20682        }
20683
20684        if old_cursor_shape != self.cursor_shape {
20685            cx.emit(EditorEvent::CursorShapeChanged);
20686        }
20687
20688        if old_show_breadcrumbs != self.show_breadcrumbs {
20689            cx.emit(EditorEvent::BreadcrumbsChanged);
20690        }
20691
20692        let project_settings = ProjectSettings::get_global(cx);
20693        self.serialize_dirty_buffers =
20694            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20695
20696        if self.mode.is_full() {
20697            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20698            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20699            if self.show_inline_diagnostics != show_inline_diagnostics {
20700                self.show_inline_diagnostics = show_inline_diagnostics;
20701                self.refresh_inline_diagnostics(false, window, cx);
20702            }
20703
20704            if self.git_blame_inline_enabled != inline_blame_enabled {
20705                self.toggle_git_blame_inline_internal(false, window, cx);
20706            }
20707
20708            let minimap_settings = EditorSettings::get_global(cx).minimap;
20709            if self.minimap_visibility != MinimapVisibility::Disabled {
20710                if self.minimap_visibility.settings_visibility()
20711                    != minimap_settings.minimap_enabled()
20712                {
20713                    self.set_minimap_visibility(
20714                        MinimapVisibility::for_mode(self.mode(), cx),
20715                        window,
20716                        cx,
20717                    );
20718                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20719                    minimap_entity.update(cx, |minimap_editor, cx| {
20720                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20721                    })
20722                }
20723            }
20724        }
20725
20726        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20727            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20728        }) {
20729            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20730                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20731            }
20732            self.refresh_colors(false, None, window, cx);
20733        }
20734
20735        cx.notify();
20736    }
20737
20738    pub fn set_searchable(&mut self, searchable: bool) {
20739        self.searchable = searchable;
20740    }
20741
20742    pub fn searchable(&self) -> bool {
20743        self.searchable
20744    }
20745
20746    fn open_proposed_changes_editor(
20747        &mut self,
20748        _: &OpenProposedChangesEditor,
20749        window: &mut Window,
20750        cx: &mut Context<Self>,
20751    ) {
20752        let Some(workspace) = self.workspace() else {
20753            cx.propagate();
20754            return;
20755        };
20756
20757        let selections = self.selections.all::<usize>(cx);
20758        let multi_buffer = self.buffer.read(cx);
20759        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20760        let mut new_selections_by_buffer = HashMap::default();
20761        for selection in selections {
20762            for (buffer, range, _) in
20763                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20764            {
20765                let mut range = range.to_point(buffer);
20766                range.start.column = 0;
20767                range.end.column = buffer.line_len(range.end.row);
20768                new_selections_by_buffer
20769                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20770                    .or_insert(Vec::new())
20771                    .push(range)
20772            }
20773        }
20774
20775        let proposed_changes_buffers = new_selections_by_buffer
20776            .into_iter()
20777            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20778            .collect::<Vec<_>>();
20779        let proposed_changes_editor = cx.new(|cx| {
20780            ProposedChangesEditor::new(
20781                "Proposed changes",
20782                proposed_changes_buffers,
20783                self.project.clone(),
20784                window,
20785                cx,
20786            )
20787        });
20788
20789        window.defer(cx, move |window, cx| {
20790            workspace.update(cx, |workspace, cx| {
20791                workspace.active_pane().update(cx, |pane, cx| {
20792                    pane.add_item(
20793                        Box::new(proposed_changes_editor),
20794                        true,
20795                        true,
20796                        None,
20797                        window,
20798                        cx,
20799                    );
20800                });
20801            });
20802        });
20803    }
20804
20805    pub fn open_excerpts_in_split(
20806        &mut self,
20807        _: &OpenExcerptsSplit,
20808        window: &mut Window,
20809        cx: &mut Context<Self>,
20810    ) {
20811        self.open_excerpts_common(None, true, window, cx)
20812    }
20813
20814    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20815        self.open_excerpts_common(None, false, window, cx)
20816    }
20817
20818    fn open_excerpts_common(
20819        &mut self,
20820        jump_data: Option<JumpData>,
20821        split: bool,
20822        window: &mut Window,
20823        cx: &mut Context<Self>,
20824    ) {
20825        let Some(workspace) = self.workspace() else {
20826            cx.propagate();
20827            return;
20828        };
20829
20830        if self.buffer.read(cx).is_singleton() {
20831            cx.propagate();
20832            return;
20833        }
20834
20835        let mut new_selections_by_buffer = HashMap::default();
20836        match &jump_data {
20837            Some(JumpData::MultiBufferPoint {
20838                excerpt_id,
20839                position,
20840                anchor,
20841                line_offset_from_top,
20842            }) => {
20843                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20844                if let Some(buffer) = multi_buffer_snapshot
20845                    .buffer_id_for_excerpt(*excerpt_id)
20846                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20847                {
20848                    let buffer_snapshot = buffer.read(cx).snapshot();
20849                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20850                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20851                    } else {
20852                        buffer_snapshot.clip_point(*position, Bias::Left)
20853                    };
20854                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20855                    new_selections_by_buffer.insert(
20856                        buffer,
20857                        (
20858                            vec![jump_to_offset..jump_to_offset],
20859                            Some(*line_offset_from_top),
20860                        ),
20861                    );
20862                }
20863            }
20864            Some(JumpData::MultiBufferRow {
20865                row,
20866                line_offset_from_top,
20867            }) => {
20868                let point = MultiBufferPoint::new(row.0, 0);
20869                if let Some((buffer, buffer_point, _)) =
20870                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20871                {
20872                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20873                    new_selections_by_buffer
20874                        .entry(buffer)
20875                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20876                        .0
20877                        .push(buffer_offset..buffer_offset)
20878                }
20879            }
20880            None => {
20881                let selections = self.selections.all::<usize>(cx);
20882                let multi_buffer = self.buffer.read(cx);
20883                for selection in selections {
20884                    for (snapshot, range, _, anchor) in multi_buffer
20885                        .snapshot(cx)
20886                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20887                    {
20888                        if let Some(anchor) = anchor {
20889                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20890                            else {
20891                                continue;
20892                            };
20893                            let offset = text::ToOffset::to_offset(
20894                                &anchor.text_anchor,
20895                                &buffer_handle.read(cx).snapshot(),
20896                            );
20897                            let range = offset..offset;
20898                            new_selections_by_buffer
20899                                .entry(buffer_handle)
20900                                .or_insert((Vec::new(), None))
20901                                .0
20902                                .push(range)
20903                        } else {
20904                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20905                            else {
20906                                continue;
20907                            };
20908                            new_selections_by_buffer
20909                                .entry(buffer_handle)
20910                                .or_insert((Vec::new(), None))
20911                                .0
20912                                .push(range)
20913                        }
20914                    }
20915                }
20916            }
20917        }
20918
20919        new_selections_by_buffer
20920            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20921
20922        if new_selections_by_buffer.is_empty() {
20923            return;
20924        }
20925
20926        // We defer the pane interaction because we ourselves are a workspace item
20927        // and activating a new item causes the pane to call a method on us reentrantly,
20928        // which panics if we're on the stack.
20929        window.defer(cx, move |window, cx| {
20930            workspace.update(cx, |workspace, cx| {
20931                let pane = if split {
20932                    workspace.adjacent_pane(window, cx)
20933                } else {
20934                    workspace.active_pane().clone()
20935                };
20936
20937                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20938                    let editor = buffer
20939                        .read(cx)
20940                        .file()
20941                        .is_none()
20942                        .then(|| {
20943                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20944                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20945                            // Instead, we try to activate the existing editor in the pane first.
20946                            let (editor, pane_item_index) =
20947                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20948                                    let editor = item.downcast::<Editor>()?;
20949                                    let singleton_buffer =
20950                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20951                                    if singleton_buffer == buffer {
20952                                        Some((editor, i))
20953                                    } else {
20954                                        None
20955                                    }
20956                                })?;
20957                            pane.update(cx, |pane, cx| {
20958                                pane.activate_item(pane_item_index, true, true, window, cx)
20959                            });
20960                            Some(editor)
20961                        })
20962                        .flatten()
20963                        .unwrap_or_else(|| {
20964                            workspace.open_project_item::<Self>(
20965                                pane.clone(),
20966                                buffer,
20967                                true,
20968                                true,
20969                                window,
20970                                cx,
20971                            )
20972                        });
20973
20974                    editor.update(cx, |editor, cx| {
20975                        let autoscroll = match scroll_offset {
20976                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20977                            None => Autoscroll::newest(),
20978                        };
20979                        let nav_history = editor.nav_history.take();
20980                        editor.change_selections(
20981                            SelectionEffects::scroll(autoscroll),
20982                            window,
20983                            cx,
20984                            |s| {
20985                                s.select_ranges(ranges);
20986                            },
20987                        );
20988                        editor.nav_history = nav_history;
20989                    });
20990                }
20991            })
20992        });
20993    }
20994
20995    // For now, don't allow opening excerpts in buffers that aren't backed by
20996    // regular project files.
20997    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20998        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
20999    }
21000
21001    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21002        let snapshot = self.buffer.read(cx).read(cx);
21003        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21004        Some(
21005            ranges
21006                .iter()
21007                .map(move |range| {
21008                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21009                })
21010                .collect(),
21011        )
21012    }
21013
21014    fn selection_replacement_ranges(
21015        &self,
21016        range: Range<OffsetUtf16>,
21017        cx: &mut App,
21018    ) -> Vec<Range<OffsetUtf16>> {
21019        let selections = self.selections.all::<OffsetUtf16>(cx);
21020        let newest_selection = selections
21021            .iter()
21022            .max_by_key(|selection| selection.id)
21023            .unwrap();
21024        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21025        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21026        let snapshot = self.buffer.read(cx).read(cx);
21027        selections
21028            .into_iter()
21029            .map(|mut selection| {
21030                selection.start.0 =
21031                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21032                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21033                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21034                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21035            })
21036            .collect()
21037    }
21038
21039    fn report_editor_event(
21040        &self,
21041        reported_event: ReportEditorEvent,
21042        file_extension: Option<String>,
21043        cx: &App,
21044    ) {
21045        if cfg!(any(test, feature = "test-support")) {
21046            return;
21047        }
21048
21049        let Some(project) = &self.project else { return };
21050
21051        // If None, we are in a file without an extension
21052        let file = self
21053            .buffer
21054            .read(cx)
21055            .as_singleton()
21056            .and_then(|b| b.read(cx).file());
21057        let file_extension = file_extension.or(file
21058            .as_ref()
21059            .and_then(|file| Path::new(file.file_name(cx)).extension())
21060            .and_then(|e| e.to_str())
21061            .map(|a| a.to_string()));
21062
21063        let vim_mode = vim_enabled(cx);
21064
21065        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21066        let copilot_enabled = edit_predictions_provider
21067            == language::language_settings::EditPredictionProvider::Copilot;
21068        let copilot_enabled_for_language = self
21069            .buffer
21070            .read(cx)
21071            .language_settings(cx)
21072            .show_edit_predictions;
21073
21074        let project = project.read(cx);
21075        let event_type = reported_event.event_type();
21076
21077        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21078            telemetry::event!(
21079                event_type,
21080                type = if auto_saved {"autosave"} else {"manual"},
21081                file_extension,
21082                vim_mode,
21083                copilot_enabled,
21084                copilot_enabled_for_language,
21085                edit_predictions_provider,
21086                is_via_ssh = project.is_via_remote_server(),
21087            );
21088        } else {
21089            telemetry::event!(
21090                event_type,
21091                file_extension,
21092                vim_mode,
21093                copilot_enabled,
21094                copilot_enabled_for_language,
21095                edit_predictions_provider,
21096                is_via_ssh = project.is_via_remote_server(),
21097            );
21098        };
21099    }
21100
21101    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21102    /// with each line being an array of {text, highlight} objects.
21103    fn copy_highlight_json(
21104        &mut self,
21105        _: &CopyHighlightJson,
21106        window: &mut Window,
21107        cx: &mut Context<Self>,
21108    ) {
21109        #[derive(Serialize)]
21110        struct Chunk<'a> {
21111            text: String,
21112            highlight: Option<&'a str>,
21113        }
21114
21115        let snapshot = self.buffer.read(cx).snapshot(cx);
21116        let range = self
21117            .selected_text_range(false, window, cx)
21118            .and_then(|selection| {
21119                if selection.range.is_empty() {
21120                    None
21121                } else {
21122                    Some(selection.range)
21123                }
21124            })
21125            .unwrap_or_else(|| 0..snapshot.len());
21126
21127        let chunks = snapshot.chunks(range, true);
21128        let mut lines = Vec::new();
21129        let mut line: VecDeque<Chunk> = VecDeque::new();
21130
21131        let Some(style) = self.style.as_ref() else {
21132            return;
21133        };
21134
21135        for chunk in chunks {
21136            let highlight = chunk
21137                .syntax_highlight_id
21138                .and_then(|id| id.name(&style.syntax));
21139            let mut chunk_lines = chunk.text.split('\n').peekable();
21140            while let Some(text) = chunk_lines.next() {
21141                let mut merged_with_last_token = false;
21142                if let Some(last_token) = line.back_mut()
21143                    && last_token.highlight == highlight
21144                {
21145                    last_token.text.push_str(text);
21146                    merged_with_last_token = true;
21147                }
21148
21149                if !merged_with_last_token {
21150                    line.push_back(Chunk {
21151                        text: text.into(),
21152                        highlight,
21153                    });
21154                }
21155
21156                if chunk_lines.peek().is_some() {
21157                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21158                        line.pop_front();
21159                    }
21160                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21161                        line.pop_back();
21162                    }
21163
21164                    lines.push(mem::take(&mut line));
21165                }
21166            }
21167        }
21168
21169        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21170            return;
21171        };
21172        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21173    }
21174
21175    pub fn open_context_menu(
21176        &mut self,
21177        _: &OpenContextMenu,
21178        window: &mut Window,
21179        cx: &mut Context<Self>,
21180    ) {
21181        self.request_autoscroll(Autoscroll::newest(), cx);
21182        let position = self.selections.newest_display(cx).start;
21183        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21184    }
21185
21186    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21187        &self.inlay_hint_cache
21188    }
21189
21190    pub fn replay_insert_event(
21191        &mut self,
21192        text: &str,
21193        relative_utf16_range: Option<Range<isize>>,
21194        window: &mut Window,
21195        cx: &mut Context<Self>,
21196    ) {
21197        if !self.input_enabled {
21198            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21199            return;
21200        }
21201        if let Some(relative_utf16_range) = relative_utf16_range {
21202            let selections = self.selections.all::<OffsetUtf16>(cx);
21203            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21204                let new_ranges = selections.into_iter().map(|range| {
21205                    let start = OffsetUtf16(
21206                        range
21207                            .head()
21208                            .0
21209                            .saturating_add_signed(relative_utf16_range.start),
21210                    );
21211                    let end = OffsetUtf16(
21212                        range
21213                            .head()
21214                            .0
21215                            .saturating_add_signed(relative_utf16_range.end),
21216                    );
21217                    start..end
21218                });
21219                s.select_ranges(new_ranges);
21220            });
21221        }
21222
21223        self.handle_input(text, window, cx);
21224    }
21225
21226    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21227        let Some(provider) = self.semantics_provider.as_ref() else {
21228            return false;
21229        };
21230
21231        let mut supports = false;
21232        self.buffer().update(cx, |this, cx| {
21233            this.for_each_buffer(|buffer| {
21234                supports |= provider.supports_inlay_hints(buffer, cx);
21235            });
21236        });
21237
21238        supports
21239    }
21240
21241    pub fn is_focused(&self, window: &Window) -> bool {
21242        self.focus_handle.is_focused(window)
21243    }
21244
21245    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21246        cx.emit(EditorEvent::Focused);
21247
21248        if let Some(descendant) = self
21249            .last_focused_descendant
21250            .take()
21251            .and_then(|descendant| descendant.upgrade())
21252        {
21253            window.focus(&descendant);
21254        } else {
21255            if let Some(blame) = self.blame.as_ref() {
21256                blame.update(cx, GitBlame::focus)
21257            }
21258
21259            self.blink_manager.update(cx, BlinkManager::enable);
21260            self.show_cursor_names(window, cx);
21261            self.buffer.update(cx, |buffer, cx| {
21262                buffer.finalize_last_transaction(cx);
21263                if self.leader_id.is_none() {
21264                    buffer.set_active_selections(
21265                        &self.selections.disjoint_anchors(),
21266                        self.selections.line_mode,
21267                        self.cursor_shape,
21268                        cx,
21269                    );
21270                }
21271            });
21272        }
21273    }
21274
21275    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21276        cx.emit(EditorEvent::FocusedIn)
21277    }
21278
21279    fn handle_focus_out(
21280        &mut self,
21281        event: FocusOutEvent,
21282        _window: &mut Window,
21283        cx: &mut Context<Self>,
21284    ) {
21285        if event.blurred != self.focus_handle {
21286            self.last_focused_descendant = Some(event.blurred);
21287        }
21288        self.selection_drag_state = SelectionDragState::None;
21289        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21290    }
21291
21292    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21293        self.blink_manager.update(cx, BlinkManager::disable);
21294        self.buffer
21295            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21296
21297        if let Some(blame) = self.blame.as_ref() {
21298            blame.update(cx, GitBlame::blur)
21299        }
21300        if !self.hover_state.focused(window, cx) {
21301            hide_hover(self, cx);
21302        }
21303        if !self
21304            .context_menu
21305            .borrow()
21306            .as_ref()
21307            .is_some_and(|context_menu| context_menu.focused(window, cx))
21308        {
21309            self.hide_context_menu(window, cx);
21310        }
21311        self.discard_edit_prediction(false, cx);
21312        cx.emit(EditorEvent::Blurred);
21313        cx.notify();
21314    }
21315
21316    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21317        let mut pending: String = window
21318            .pending_input_keystrokes()
21319            .into_iter()
21320            .flatten()
21321            .filter_map(|keystroke| {
21322                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21323                    keystroke.key_char.clone()
21324                } else {
21325                    None
21326                }
21327            })
21328            .collect();
21329
21330        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21331            pending = "".to_string();
21332        }
21333
21334        let existing_pending = self
21335            .text_highlights::<PendingInput>(cx)
21336            .map(|(_, ranges)| ranges.to_vec());
21337        if existing_pending.is_none() && pending.is_empty() {
21338            return;
21339        }
21340        let transaction =
21341            self.transact(window, cx, |this, window, cx| {
21342                let selections = this.selections.all::<usize>(cx);
21343                let edits = selections
21344                    .iter()
21345                    .map(|selection| (selection.end..selection.end, pending.clone()));
21346                this.edit(edits, cx);
21347                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21348                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21349                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21350                    }));
21351                });
21352                if let Some(existing_ranges) = existing_pending {
21353                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21354                    this.edit(edits, cx);
21355                }
21356            });
21357
21358        let snapshot = self.snapshot(window, cx);
21359        let ranges = self
21360            .selections
21361            .all::<usize>(cx)
21362            .into_iter()
21363            .map(|selection| {
21364                snapshot.buffer_snapshot.anchor_after(selection.end)
21365                    ..snapshot
21366                        .buffer_snapshot
21367                        .anchor_before(selection.end + pending.len())
21368            })
21369            .collect();
21370
21371        if pending.is_empty() {
21372            self.clear_highlights::<PendingInput>(cx);
21373        } else {
21374            self.highlight_text::<PendingInput>(
21375                ranges,
21376                HighlightStyle {
21377                    underline: Some(UnderlineStyle {
21378                        thickness: px(1.),
21379                        color: None,
21380                        wavy: false,
21381                    }),
21382                    ..Default::default()
21383                },
21384                cx,
21385            );
21386        }
21387
21388        self.ime_transaction = self.ime_transaction.or(transaction);
21389        if let Some(transaction) = self.ime_transaction {
21390            self.buffer.update(cx, |buffer, cx| {
21391                buffer.group_until_transaction(transaction, cx);
21392            });
21393        }
21394
21395        if self.text_highlights::<PendingInput>(cx).is_none() {
21396            self.ime_transaction.take();
21397        }
21398    }
21399
21400    pub fn register_action_renderer(
21401        &mut self,
21402        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21403    ) -> Subscription {
21404        let id = self.next_editor_action_id.post_inc();
21405        self.editor_actions
21406            .borrow_mut()
21407            .insert(id, Box::new(listener));
21408
21409        let editor_actions = self.editor_actions.clone();
21410        Subscription::new(move || {
21411            editor_actions.borrow_mut().remove(&id);
21412        })
21413    }
21414
21415    pub fn register_action<A: Action>(
21416        &mut self,
21417        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21418    ) -> Subscription {
21419        let id = self.next_editor_action_id.post_inc();
21420        let listener = Arc::new(listener);
21421        self.editor_actions.borrow_mut().insert(
21422            id,
21423            Box::new(move |_, window, _| {
21424                let listener = listener.clone();
21425                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21426                    let action = action.downcast_ref().unwrap();
21427                    if phase == DispatchPhase::Bubble {
21428                        listener(action, window, cx)
21429                    }
21430                })
21431            }),
21432        );
21433
21434        let editor_actions = self.editor_actions.clone();
21435        Subscription::new(move || {
21436            editor_actions.borrow_mut().remove(&id);
21437        })
21438    }
21439
21440    pub fn file_header_size(&self) -> u32 {
21441        FILE_HEADER_HEIGHT
21442    }
21443
21444    pub fn restore(
21445        &mut self,
21446        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21447        window: &mut Window,
21448        cx: &mut Context<Self>,
21449    ) {
21450        let workspace = self.workspace();
21451        let project = self.project();
21452        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21453            let mut tasks = Vec::new();
21454            for (buffer_id, changes) in revert_changes {
21455                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21456                    buffer.update(cx, |buffer, cx| {
21457                        buffer.edit(
21458                            changes
21459                                .into_iter()
21460                                .map(|(range, text)| (range, text.to_string())),
21461                            None,
21462                            cx,
21463                        );
21464                    });
21465
21466                    if let Some(project) =
21467                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21468                    {
21469                        project.update(cx, |project, cx| {
21470                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21471                        })
21472                    }
21473                }
21474            }
21475            tasks
21476        });
21477        cx.spawn_in(window, async move |_, cx| {
21478            for (buffer, task) in save_tasks {
21479                let result = task.await;
21480                if result.is_err() {
21481                    let Some(path) = buffer
21482                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21483                        .ok()
21484                    else {
21485                        continue;
21486                    };
21487                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21488                        let Some(task) = cx
21489                            .update_window_entity(workspace, |workspace, window, cx| {
21490                                workspace
21491                                    .open_path_preview(path, None, false, false, false, window, cx)
21492                            })
21493                            .ok()
21494                        else {
21495                            continue;
21496                        };
21497                        task.await.log_err();
21498                    }
21499                }
21500            }
21501        })
21502        .detach();
21503        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21504            selections.refresh()
21505        });
21506    }
21507
21508    pub fn to_pixel_point(
21509        &self,
21510        source: multi_buffer::Anchor,
21511        editor_snapshot: &EditorSnapshot,
21512        window: &mut Window,
21513    ) -> Option<gpui::Point<Pixels>> {
21514        let source_point = source.to_display_point(editor_snapshot);
21515        self.display_to_pixel_point(source_point, editor_snapshot, window)
21516    }
21517
21518    pub fn display_to_pixel_point(
21519        &self,
21520        source: DisplayPoint,
21521        editor_snapshot: &EditorSnapshot,
21522        window: &mut Window,
21523    ) -> Option<gpui::Point<Pixels>> {
21524        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21525        let text_layout_details = self.text_layout_details(window);
21526        let scroll_top = text_layout_details
21527            .scroll_anchor
21528            .scroll_position(editor_snapshot)
21529            .y;
21530
21531        if source.row().as_f32() < scroll_top.floor() {
21532            return None;
21533        }
21534        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21535        let source_y = line_height * (source.row().as_f32() - scroll_top);
21536        Some(gpui::Point::new(source_x, source_y))
21537    }
21538
21539    pub fn has_visible_completions_menu(&self) -> bool {
21540        !self.edit_prediction_preview_is_active()
21541            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21542                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21543            })
21544    }
21545
21546    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21547        if self.mode.is_minimap() {
21548            return;
21549        }
21550        self.addons
21551            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21552    }
21553
21554    pub fn unregister_addon<T: Addon>(&mut self) {
21555        self.addons.remove(&std::any::TypeId::of::<T>());
21556    }
21557
21558    pub fn addon<T: Addon>(&self) -> Option<&T> {
21559        let type_id = std::any::TypeId::of::<T>();
21560        self.addons
21561            .get(&type_id)
21562            .and_then(|item| item.to_any().downcast_ref::<T>())
21563    }
21564
21565    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21566        let type_id = std::any::TypeId::of::<T>();
21567        self.addons
21568            .get_mut(&type_id)
21569            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21570    }
21571
21572    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21573        let text_layout_details = self.text_layout_details(window);
21574        let style = &text_layout_details.editor_style;
21575        let font_id = window.text_system().resolve_font(&style.text.font());
21576        let font_size = style.text.font_size.to_pixels(window.rem_size());
21577        let line_height = style.text.line_height_in_pixels(window.rem_size());
21578        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21579        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21580
21581        CharacterDimensions {
21582            em_width,
21583            em_advance,
21584            line_height,
21585        }
21586    }
21587
21588    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21589        self.load_diff_task.clone()
21590    }
21591
21592    fn read_metadata_from_db(
21593        &mut self,
21594        item_id: u64,
21595        workspace_id: WorkspaceId,
21596        window: &mut Window,
21597        cx: &mut Context<Editor>,
21598    ) {
21599        if self.is_singleton(cx)
21600            && !self.mode.is_minimap()
21601            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21602        {
21603            let buffer_snapshot = OnceCell::new();
21604
21605            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21606                && !folds.is_empty()
21607            {
21608                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21609                self.fold_ranges(
21610                    folds
21611                        .into_iter()
21612                        .map(|(start, end)| {
21613                            snapshot.clip_offset(start, Bias::Left)
21614                                ..snapshot.clip_offset(end, Bias::Right)
21615                        })
21616                        .collect(),
21617                    false,
21618                    window,
21619                    cx,
21620                );
21621            }
21622
21623            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21624                && !selections.is_empty()
21625            {
21626                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21627                // skip adding the initial selection to selection history
21628                self.selection_history.mode = SelectionHistoryMode::Skipping;
21629                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21630                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21631                        snapshot.clip_offset(start, Bias::Left)
21632                            ..snapshot.clip_offset(end, Bias::Right)
21633                    }));
21634                });
21635                self.selection_history.mode = SelectionHistoryMode::Normal;
21636            };
21637        }
21638
21639        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21640    }
21641
21642    fn update_lsp_data(
21643        &mut self,
21644        ignore_cache: bool,
21645        for_buffer: Option<BufferId>,
21646        window: &mut Window,
21647        cx: &mut Context<'_, Self>,
21648    ) {
21649        self.pull_diagnostics(for_buffer, window, cx);
21650        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21651    }
21652}
21653
21654fn vim_enabled(cx: &App) -> bool {
21655    cx.global::<SettingsStore>()
21656        .raw_user_settings()
21657        .get("vim_mode")
21658        == Some(&serde_json::Value::Bool(true))
21659}
21660
21661fn process_completion_for_edit(
21662    completion: &Completion,
21663    intent: CompletionIntent,
21664    buffer: &Entity<Buffer>,
21665    cursor_position: &text::Anchor,
21666    cx: &mut Context<Editor>,
21667) -> CompletionEdit {
21668    let buffer = buffer.read(cx);
21669    let buffer_snapshot = buffer.snapshot();
21670    let (snippet, new_text) = if completion.is_snippet() {
21671        // Workaround for typescript language server issues so that methods don't expand within
21672        // strings and functions with type expressions. The previous point is used because the query
21673        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21674        let mut snippet_source = completion.new_text.clone();
21675        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21676        previous_point.column = previous_point.column.saturating_sub(1);
21677        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21678            && scope.prefers_label_for_snippet_in_completion()
21679            && let Some(label) = completion.label()
21680            && matches!(
21681                completion.kind(),
21682                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21683            )
21684        {
21685            snippet_source = label;
21686        }
21687        match Snippet::parse(&snippet_source).log_err() {
21688            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21689            None => (None, completion.new_text.clone()),
21690        }
21691    } else {
21692        (None, completion.new_text.clone())
21693    };
21694
21695    let mut range_to_replace = {
21696        let replace_range = &completion.replace_range;
21697        if let CompletionSource::Lsp {
21698            insert_range: Some(insert_range),
21699            ..
21700        } = &completion.source
21701        {
21702            debug_assert_eq!(
21703                insert_range.start, replace_range.start,
21704                "insert_range and replace_range should start at the same position"
21705            );
21706            debug_assert!(
21707                insert_range
21708                    .start
21709                    .cmp(cursor_position, &buffer_snapshot)
21710                    .is_le(),
21711                "insert_range should start before or at cursor position"
21712            );
21713            debug_assert!(
21714                replace_range
21715                    .start
21716                    .cmp(cursor_position, &buffer_snapshot)
21717                    .is_le(),
21718                "replace_range should start before or at cursor position"
21719            );
21720
21721            let should_replace = match intent {
21722                CompletionIntent::CompleteWithInsert => false,
21723                CompletionIntent::CompleteWithReplace => true,
21724                CompletionIntent::Complete | CompletionIntent::Compose => {
21725                    let insert_mode =
21726                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21727                            .completions
21728                            .lsp_insert_mode;
21729                    match insert_mode {
21730                        LspInsertMode::Insert => false,
21731                        LspInsertMode::Replace => true,
21732                        LspInsertMode::ReplaceSubsequence => {
21733                            let mut text_to_replace = buffer.chars_for_range(
21734                                buffer.anchor_before(replace_range.start)
21735                                    ..buffer.anchor_after(replace_range.end),
21736                            );
21737                            let mut current_needle = text_to_replace.next();
21738                            for haystack_ch in completion.label.text.chars() {
21739                                if let Some(needle_ch) = current_needle
21740                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21741                                {
21742                                    current_needle = text_to_replace.next();
21743                                }
21744                            }
21745                            current_needle.is_none()
21746                        }
21747                        LspInsertMode::ReplaceSuffix => {
21748                            if replace_range
21749                                .end
21750                                .cmp(cursor_position, &buffer_snapshot)
21751                                .is_gt()
21752                            {
21753                                let range_after_cursor = *cursor_position..replace_range.end;
21754                                let text_after_cursor = buffer
21755                                    .text_for_range(
21756                                        buffer.anchor_before(range_after_cursor.start)
21757                                            ..buffer.anchor_after(range_after_cursor.end),
21758                                    )
21759                                    .collect::<String>()
21760                                    .to_ascii_lowercase();
21761                                completion
21762                                    .label
21763                                    .text
21764                                    .to_ascii_lowercase()
21765                                    .ends_with(&text_after_cursor)
21766                            } else {
21767                                true
21768                            }
21769                        }
21770                    }
21771                }
21772            };
21773
21774            if should_replace {
21775                replace_range.clone()
21776            } else {
21777                insert_range.clone()
21778            }
21779        } else {
21780            replace_range.clone()
21781        }
21782    };
21783
21784    if range_to_replace
21785        .end
21786        .cmp(cursor_position, &buffer_snapshot)
21787        .is_lt()
21788    {
21789        range_to_replace.end = *cursor_position;
21790    }
21791
21792    CompletionEdit {
21793        new_text,
21794        replace_range: range_to_replace.to_offset(buffer),
21795        snippet,
21796    }
21797}
21798
21799struct CompletionEdit {
21800    new_text: String,
21801    replace_range: Range<usize>,
21802    snippet: Option<Snippet>,
21803}
21804
21805fn insert_extra_newline_brackets(
21806    buffer: &MultiBufferSnapshot,
21807    range: Range<usize>,
21808    language: &language::LanguageScope,
21809) -> bool {
21810    let leading_whitespace_len = buffer
21811        .reversed_chars_at(range.start)
21812        .take_while(|c| c.is_whitespace() && *c != '\n')
21813        .map(|c| c.len_utf8())
21814        .sum::<usize>();
21815    let trailing_whitespace_len = buffer
21816        .chars_at(range.end)
21817        .take_while(|c| c.is_whitespace() && *c != '\n')
21818        .map(|c| c.len_utf8())
21819        .sum::<usize>();
21820    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21821
21822    language.brackets().any(|(pair, enabled)| {
21823        let pair_start = pair.start.trim_end();
21824        let pair_end = pair.end.trim_start();
21825
21826        enabled
21827            && pair.newline
21828            && buffer.contains_str_at(range.end, pair_end)
21829            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21830    })
21831}
21832
21833fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21834    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21835        [(buffer, range, _)] => (*buffer, range.clone()),
21836        _ => return false,
21837    };
21838    let pair = {
21839        let mut result: Option<BracketMatch> = None;
21840
21841        for pair in buffer
21842            .all_bracket_ranges(range.clone())
21843            .filter(move |pair| {
21844                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21845            })
21846        {
21847            let len = pair.close_range.end - pair.open_range.start;
21848
21849            if let Some(existing) = &result {
21850                let existing_len = existing.close_range.end - existing.open_range.start;
21851                if len > existing_len {
21852                    continue;
21853                }
21854            }
21855
21856            result = Some(pair);
21857        }
21858
21859        result
21860    };
21861    let Some(pair) = pair else {
21862        return false;
21863    };
21864    pair.newline_only
21865        && buffer
21866            .chars_for_range(pair.open_range.end..range.start)
21867            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21868            .all(|c| c.is_whitespace() && c != '\n')
21869}
21870
21871fn update_uncommitted_diff_for_buffer(
21872    editor: Entity<Editor>,
21873    project: &Entity<Project>,
21874    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21875    buffer: Entity<MultiBuffer>,
21876    cx: &mut App,
21877) -> Task<()> {
21878    let mut tasks = Vec::new();
21879    project.update(cx, |project, cx| {
21880        for buffer in buffers {
21881            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21882                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21883            }
21884        }
21885    });
21886    cx.spawn(async move |cx| {
21887        let diffs = future::join_all(tasks).await;
21888        if editor
21889            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21890            .unwrap_or(false)
21891        {
21892            return;
21893        }
21894
21895        buffer
21896            .update(cx, |buffer, cx| {
21897                for diff in diffs.into_iter().flatten() {
21898                    buffer.add_diff(diff, cx);
21899                }
21900            })
21901            .ok();
21902    })
21903}
21904
21905fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21906    let tab_size = tab_size.get() as usize;
21907    let mut width = offset;
21908
21909    for ch in text.chars() {
21910        width += if ch == '\t' {
21911            tab_size - (width % tab_size)
21912        } else {
21913            1
21914        };
21915    }
21916
21917    width - offset
21918}
21919
21920#[cfg(test)]
21921mod tests {
21922    use super::*;
21923
21924    #[test]
21925    fn test_string_size_with_expanded_tabs() {
21926        let nz = |val| NonZeroU32::new(val).unwrap();
21927        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21928        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21929        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21930        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21931        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21932        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21933        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21934        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21935    }
21936}
21937
21938/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21939struct WordBreakingTokenizer<'a> {
21940    input: &'a str,
21941}
21942
21943impl<'a> WordBreakingTokenizer<'a> {
21944    fn new(input: &'a str) -> Self {
21945        Self { input }
21946    }
21947}
21948
21949fn is_char_ideographic(ch: char) -> bool {
21950    use unicode_script::Script::*;
21951    use unicode_script::UnicodeScript;
21952    matches!(ch.script(), Han | Tangut | Yi)
21953}
21954
21955fn is_grapheme_ideographic(text: &str) -> bool {
21956    text.chars().any(is_char_ideographic)
21957}
21958
21959fn is_grapheme_whitespace(text: &str) -> bool {
21960    text.chars().any(|x| x.is_whitespace())
21961}
21962
21963fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21964    text.chars()
21965        .next()
21966        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21967}
21968
21969#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21970enum WordBreakToken<'a> {
21971    Word { token: &'a str, grapheme_len: usize },
21972    InlineWhitespace { token: &'a str, grapheme_len: usize },
21973    Newline,
21974}
21975
21976impl<'a> Iterator for WordBreakingTokenizer<'a> {
21977    /// Yields a span, the count of graphemes in the token, and whether it was
21978    /// whitespace. Note that it also breaks at word boundaries.
21979    type Item = WordBreakToken<'a>;
21980
21981    fn next(&mut self) -> Option<Self::Item> {
21982        use unicode_segmentation::UnicodeSegmentation;
21983        if self.input.is_empty() {
21984            return None;
21985        }
21986
21987        let mut iter = self.input.graphemes(true).peekable();
21988        let mut offset = 0;
21989        let mut grapheme_len = 0;
21990        if let Some(first_grapheme) = iter.next() {
21991            let is_newline = first_grapheme == "\n";
21992            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21993            offset += first_grapheme.len();
21994            grapheme_len += 1;
21995            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21996                if let Some(grapheme) = iter.peek().copied()
21997                    && should_stay_with_preceding_ideograph(grapheme)
21998                {
21999                    offset += grapheme.len();
22000                    grapheme_len += 1;
22001                }
22002            } else {
22003                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22004                let mut next_word_bound = words.peek().copied();
22005                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22006                    next_word_bound = words.next();
22007                }
22008                while let Some(grapheme) = iter.peek().copied() {
22009                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22010                        break;
22011                    };
22012                    if is_grapheme_whitespace(grapheme) != is_whitespace
22013                        || (grapheme == "\n") != is_newline
22014                    {
22015                        break;
22016                    };
22017                    offset += grapheme.len();
22018                    grapheme_len += 1;
22019                    iter.next();
22020                }
22021            }
22022            let token = &self.input[..offset];
22023            self.input = &self.input[offset..];
22024            if token == "\n" {
22025                Some(WordBreakToken::Newline)
22026            } else if is_whitespace {
22027                Some(WordBreakToken::InlineWhitespace {
22028                    token,
22029                    grapheme_len,
22030                })
22031            } else {
22032                Some(WordBreakToken::Word {
22033                    token,
22034                    grapheme_len,
22035                })
22036            }
22037        } else {
22038            None
22039        }
22040    }
22041}
22042
22043#[test]
22044fn test_word_breaking_tokenizer() {
22045    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22046        ("", &[]),
22047        ("  ", &[whitespace("  ", 2)]),
22048        ("Ʒ", &[word("Ʒ", 1)]),
22049        ("Ǽ", &[word("Ǽ", 1)]),
22050        ("", &[word("", 1)]),
22051        ("⋑⋑", &[word("⋑⋑", 2)]),
22052        (
22053            "原理,进而",
22054            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22055        ),
22056        (
22057            "hello world",
22058            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22059        ),
22060        (
22061            "hello, world",
22062            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22063        ),
22064        (
22065            "  hello world",
22066            &[
22067                whitespace("  ", 2),
22068                word("hello", 5),
22069                whitespace(" ", 1),
22070                word("world", 5),
22071            ],
22072        ),
22073        (
22074            "这是什么 \n 钢笔",
22075            &[
22076                word("", 1),
22077                word("", 1),
22078                word("", 1),
22079                word("", 1),
22080                whitespace(" ", 1),
22081                newline(),
22082                whitespace(" ", 1),
22083                word("", 1),
22084                word("", 1),
22085            ],
22086        ),
22087        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22088    ];
22089
22090    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22091        WordBreakToken::Word {
22092            token,
22093            grapheme_len,
22094        }
22095    }
22096
22097    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22098        WordBreakToken::InlineWhitespace {
22099            token,
22100            grapheme_len,
22101        }
22102    }
22103
22104    fn newline() -> WordBreakToken<'static> {
22105        WordBreakToken::Newline
22106    }
22107
22108    for (input, result) in tests {
22109        assert_eq!(
22110            WordBreakingTokenizer::new(input)
22111                .collect::<Vec<_>>()
22112                .as_slice(),
22113            *result,
22114        );
22115    }
22116}
22117
22118fn wrap_with_prefix(
22119    first_line_prefix: String,
22120    subsequent_lines_prefix: String,
22121    unwrapped_text: String,
22122    wrap_column: usize,
22123    tab_size: NonZeroU32,
22124    preserve_existing_whitespace: bool,
22125) -> String {
22126    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22127    let subsequent_lines_prefix_len =
22128        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22129    let mut wrapped_text = String::new();
22130    let mut current_line = first_line_prefix;
22131    let mut is_first_line = true;
22132
22133    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22134    let mut current_line_len = first_line_prefix_len;
22135    let mut in_whitespace = false;
22136    for token in tokenizer {
22137        let have_preceding_whitespace = in_whitespace;
22138        match token {
22139            WordBreakToken::Word {
22140                token,
22141                grapheme_len,
22142            } => {
22143                in_whitespace = false;
22144                let current_prefix_len = if is_first_line {
22145                    first_line_prefix_len
22146                } else {
22147                    subsequent_lines_prefix_len
22148                };
22149                if current_line_len + grapheme_len > wrap_column
22150                    && current_line_len != current_prefix_len
22151                {
22152                    wrapped_text.push_str(current_line.trim_end());
22153                    wrapped_text.push('\n');
22154                    is_first_line = false;
22155                    current_line = subsequent_lines_prefix.clone();
22156                    current_line_len = subsequent_lines_prefix_len;
22157                }
22158                current_line.push_str(token);
22159                current_line_len += grapheme_len;
22160            }
22161            WordBreakToken::InlineWhitespace {
22162                mut token,
22163                mut grapheme_len,
22164            } => {
22165                in_whitespace = true;
22166                if have_preceding_whitespace && !preserve_existing_whitespace {
22167                    continue;
22168                }
22169                if !preserve_existing_whitespace {
22170                    token = " ";
22171                    grapheme_len = 1;
22172                }
22173                let current_prefix_len = if is_first_line {
22174                    first_line_prefix_len
22175                } else {
22176                    subsequent_lines_prefix_len
22177                };
22178                if current_line_len + grapheme_len > wrap_column {
22179                    wrapped_text.push_str(current_line.trim_end());
22180                    wrapped_text.push('\n');
22181                    is_first_line = false;
22182                    current_line = subsequent_lines_prefix.clone();
22183                    current_line_len = subsequent_lines_prefix_len;
22184                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22185                    current_line.push_str(token);
22186                    current_line_len += grapheme_len;
22187                }
22188            }
22189            WordBreakToken::Newline => {
22190                in_whitespace = true;
22191                let current_prefix_len = if is_first_line {
22192                    first_line_prefix_len
22193                } else {
22194                    subsequent_lines_prefix_len
22195                };
22196                if preserve_existing_whitespace {
22197                    wrapped_text.push_str(current_line.trim_end());
22198                    wrapped_text.push('\n');
22199                    is_first_line = false;
22200                    current_line = subsequent_lines_prefix.clone();
22201                    current_line_len = subsequent_lines_prefix_len;
22202                } else if have_preceding_whitespace {
22203                    continue;
22204                } else if current_line_len + 1 > wrap_column
22205                    && current_line_len != current_prefix_len
22206                {
22207                    wrapped_text.push_str(current_line.trim_end());
22208                    wrapped_text.push('\n');
22209                    is_first_line = false;
22210                    current_line = subsequent_lines_prefix.clone();
22211                    current_line_len = subsequent_lines_prefix_len;
22212                } else if current_line_len != current_prefix_len {
22213                    current_line.push(' ');
22214                    current_line_len += 1;
22215                }
22216            }
22217        }
22218    }
22219
22220    if !current_line.is_empty() {
22221        wrapped_text.push_str(&current_line);
22222    }
22223    wrapped_text
22224}
22225
22226#[test]
22227fn test_wrap_with_prefix() {
22228    assert_eq!(
22229        wrap_with_prefix(
22230            "# ".to_string(),
22231            "# ".to_string(),
22232            "abcdefg".to_string(),
22233            4,
22234            NonZeroU32::new(4).unwrap(),
22235            false,
22236        ),
22237        "# abcdefg"
22238    );
22239    assert_eq!(
22240        wrap_with_prefix(
22241            "".to_string(),
22242            "".to_string(),
22243            "\thello world".to_string(),
22244            8,
22245            NonZeroU32::new(4).unwrap(),
22246            false,
22247        ),
22248        "hello\nworld"
22249    );
22250    assert_eq!(
22251        wrap_with_prefix(
22252            "// ".to_string(),
22253            "// ".to_string(),
22254            "xx \nyy zz aa bb cc".to_string(),
22255            12,
22256            NonZeroU32::new(4).unwrap(),
22257            false,
22258        ),
22259        "// xx yy zz\n// aa bb cc"
22260    );
22261    assert_eq!(
22262        wrap_with_prefix(
22263            String::new(),
22264            String::new(),
22265            "这是什么 \n 钢笔".to_string(),
22266            3,
22267            NonZeroU32::new(4).unwrap(),
22268            false,
22269        ),
22270        "这是什\n么 钢\n"
22271    );
22272}
22273
22274pub trait CollaborationHub {
22275    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22276    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22277    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22278}
22279
22280impl CollaborationHub for Entity<Project> {
22281    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22282        self.read(cx).collaborators()
22283    }
22284
22285    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22286        self.read(cx).user_store().read(cx).participant_indices()
22287    }
22288
22289    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22290        let this = self.read(cx);
22291        let user_ids = this.collaborators().values().map(|c| c.user_id);
22292        this.user_store().read(cx).participant_names(user_ids, cx)
22293    }
22294}
22295
22296pub trait SemanticsProvider {
22297    fn hover(
22298        &self,
22299        buffer: &Entity<Buffer>,
22300        position: text::Anchor,
22301        cx: &mut App,
22302    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22303
22304    fn inline_values(
22305        &self,
22306        buffer_handle: Entity<Buffer>,
22307        range: Range<text::Anchor>,
22308        cx: &mut App,
22309    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22310
22311    fn inlay_hints(
22312        &self,
22313        buffer_handle: Entity<Buffer>,
22314        range: Range<text::Anchor>,
22315        cx: &mut App,
22316    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22317
22318    fn resolve_inlay_hint(
22319        &self,
22320        hint: InlayHint,
22321        buffer_handle: Entity<Buffer>,
22322        server_id: LanguageServerId,
22323        cx: &mut App,
22324    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22325
22326    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22327
22328    fn document_highlights(
22329        &self,
22330        buffer: &Entity<Buffer>,
22331        position: text::Anchor,
22332        cx: &mut App,
22333    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22334
22335    fn definitions(
22336        &self,
22337        buffer: &Entity<Buffer>,
22338        position: text::Anchor,
22339        kind: GotoDefinitionKind,
22340        cx: &mut App,
22341    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22342
22343    fn range_for_rename(
22344        &self,
22345        buffer: &Entity<Buffer>,
22346        position: text::Anchor,
22347        cx: &mut App,
22348    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22349
22350    fn perform_rename(
22351        &self,
22352        buffer: &Entity<Buffer>,
22353        position: text::Anchor,
22354        new_name: String,
22355        cx: &mut App,
22356    ) -> Option<Task<Result<ProjectTransaction>>>;
22357}
22358
22359pub trait CompletionProvider {
22360    fn completions(
22361        &self,
22362        excerpt_id: ExcerptId,
22363        buffer: &Entity<Buffer>,
22364        buffer_position: text::Anchor,
22365        trigger: CompletionContext,
22366        window: &mut Window,
22367        cx: &mut Context<Editor>,
22368    ) -> Task<Result<Vec<CompletionResponse>>>;
22369
22370    fn resolve_completions(
22371        &self,
22372        _buffer: Entity<Buffer>,
22373        _completion_indices: Vec<usize>,
22374        _completions: Rc<RefCell<Box<[Completion]>>>,
22375        _cx: &mut Context<Editor>,
22376    ) -> Task<Result<bool>> {
22377        Task::ready(Ok(false))
22378    }
22379
22380    fn apply_additional_edits_for_completion(
22381        &self,
22382        _buffer: Entity<Buffer>,
22383        _completions: Rc<RefCell<Box<[Completion]>>>,
22384        _completion_index: usize,
22385        _push_to_history: bool,
22386        _cx: &mut Context<Editor>,
22387    ) -> Task<Result<Option<language::Transaction>>> {
22388        Task::ready(Ok(None))
22389    }
22390
22391    fn is_completion_trigger(
22392        &self,
22393        buffer: &Entity<Buffer>,
22394        position: language::Anchor,
22395        text: &str,
22396        trigger_in_words: bool,
22397        menu_is_open: bool,
22398        cx: &mut Context<Editor>,
22399    ) -> bool;
22400
22401    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22402
22403    fn sort_completions(&self) -> bool {
22404        true
22405    }
22406
22407    fn filter_completions(&self) -> bool {
22408        true
22409    }
22410}
22411
22412pub trait CodeActionProvider {
22413    fn id(&self) -> Arc<str>;
22414
22415    fn code_actions(
22416        &self,
22417        buffer: &Entity<Buffer>,
22418        range: Range<text::Anchor>,
22419        window: &mut Window,
22420        cx: &mut App,
22421    ) -> Task<Result<Vec<CodeAction>>>;
22422
22423    fn apply_code_action(
22424        &self,
22425        buffer_handle: Entity<Buffer>,
22426        action: CodeAction,
22427        excerpt_id: ExcerptId,
22428        push_to_history: bool,
22429        window: &mut Window,
22430        cx: &mut App,
22431    ) -> Task<Result<ProjectTransaction>>;
22432}
22433
22434impl CodeActionProvider for Entity<Project> {
22435    fn id(&self) -> Arc<str> {
22436        "project".into()
22437    }
22438
22439    fn code_actions(
22440        &self,
22441        buffer: &Entity<Buffer>,
22442        range: Range<text::Anchor>,
22443        _window: &mut Window,
22444        cx: &mut App,
22445    ) -> Task<Result<Vec<CodeAction>>> {
22446        self.update(cx, |project, cx| {
22447            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22448            let code_actions = project.code_actions(buffer, range, None, cx);
22449            cx.background_spawn(async move {
22450                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22451                Ok(code_lens_actions
22452                    .context("code lens fetch")?
22453                    .into_iter()
22454                    .flatten()
22455                    .chain(
22456                        code_actions
22457                            .context("code action fetch")?
22458                            .into_iter()
22459                            .flatten(),
22460                    )
22461                    .collect())
22462            })
22463        })
22464    }
22465
22466    fn apply_code_action(
22467        &self,
22468        buffer_handle: Entity<Buffer>,
22469        action: CodeAction,
22470        _excerpt_id: ExcerptId,
22471        push_to_history: bool,
22472        _window: &mut Window,
22473        cx: &mut App,
22474    ) -> Task<Result<ProjectTransaction>> {
22475        self.update(cx, |project, cx| {
22476            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22477        })
22478    }
22479}
22480
22481fn snippet_completions(
22482    project: &Project,
22483    buffer: &Entity<Buffer>,
22484    buffer_position: text::Anchor,
22485    cx: &mut App,
22486) -> Task<Result<CompletionResponse>> {
22487    let languages = buffer.read(cx).languages_at(buffer_position);
22488    let snippet_store = project.snippets().read(cx);
22489
22490    let scopes: Vec<_> = languages
22491        .iter()
22492        .filter_map(|language| {
22493            let language_name = language.lsp_id();
22494            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22495
22496            if snippets.is_empty() {
22497                None
22498            } else {
22499                Some((language.default_scope(), snippets))
22500            }
22501        })
22502        .collect();
22503
22504    if scopes.is_empty() {
22505        return Task::ready(Ok(CompletionResponse {
22506            completions: vec![],
22507            display_options: CompletionDisplayOptions::default(),
22508            is_incomplete: false,
22509        }));
22510    }
22511
22512    let snapshot = buffer.read(cx).text_snapshot();
22513    let chars: String = snapshot
22514        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22515        .collect();
22516    let executor = cx.background_executor().clone();
22517
22518    cx.background_spawn(async move {
22519        let mut is_incomplete = false;
22520        let mut completions: Vec<Completion> = Vec::new();
22521        for (scope, snippets) in scopes.into_iter() {
22522            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22523            let mut last_word = chars
22524                .chars()
22525                .take_while(|c| classifier.is_word(*c))
22526                .collect::<String>();
22527            last_word = last_word.chars().rev().collect();
22528
22529            if last_word.is_empty() {
22530                return Ok(CompletionResponse {
22531                    completions: vec![],
22532                    display_options: CompletionDisplayOptions::default(),
22533                    is_incomplete: true,
22534                });
22535            }
22536
22537            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22538            let to_lsp = |point: &text::Anchor| {
22539                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22540                point_to_lsp(end)
22541            };
22542            let lsp_end = to_lsp(&buffer_position);
22543
22544            let candidates = snippets
22545                .iter()
22546                .enumerate()
22547                .flat_map(|(ix, snippet)| {
22548                    snippet
22549                        .prefix
22550                        .iter()
22551                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22552                })
22553                .collect::<Vec<StringMatchCandidate>>();
22554
22555            const MAX_RESULTS: usize = 100;
22556            let mut matches = fuzzy::match_strings(
22557                &candidates,
22558                &last_word,
22559                last_word.chars().any(|c| c.is_uppercase()),
22560                true,
22561                MAX_RESULTS,
22562                &Default::default(),
22563                executor.clone(),
22564            )
22565            .await;
22566
22567            if matches.len() >= MAX_RESULTS {
22568                is_incomplete = true;
22569            }
22570
22571            // Remove all candidates where the query's start does not match the start of any word in the candidate
22572            if let Some(query_start) = last_word.chars().next() {
22573                matches.retain(|string_match| {
22574                    split_words(&string_match.string).any(|word| {
22575                        // Check that the first codepoint of the word as lowercase matches the first
22576                        // codepoint of the query as lowercase
22577                        word.chars()
22578                            .flat_map(|codepoint| codepoint.to_lowercase())
22579                            .zip(query_start.to_lowercase())
22580                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22581                    })
22582                });
22583            }
22584
22585            let matched_strings = matches
22586                .into_iter()
22587                .map(|m| m.string)
22588                .collect::<HashSet<_>>();
22589
22590            completions.extend(snippets.iter().filter_map(|snippet| {
22591                let matching_prefix = snippet
22592                    .prefix
22593                    .iter()
22594                    .find(|prefix| matched_strings.contains(*prefix))?;
22595                let start = as_offset - last_word.len();
22596                let start = snapshot.anchor_before(start);
22597                let range = start..buffer_position;
22598                let lsp_start = to_lsp(&start);
22599                let lsp_range = lsp::Range {
22600                    start: lsp_start,
22601                    end: lsp_end,
22602                };
22603                Some(Completion {
22604                    replace_range: range,
22605                    new_text: snippet.body.clone(),
22606                    source: CompletionSource::Lsp {
22607                        insert_range: None,
22608                        server_id: LanguageServerId(usize::MAX),
22609                        resolved: true,
22610                        lsp_completion: Box::new(lsp::CompletionItem {
22611                            label: snippet.prefix.first().unwrap().clone(),
22612                            kind: Some(CompletionItemKind::SNIPPET),
22613                            label_details: snippet.description.as_ref().map(|description| {
22614                                lsp::CompletionItemLabelDetails {
22615                                    detail: Some(description.clone()),
22616                                    description: None,
22617                                }
22618                            }),
22619                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22620                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22621                                lsp::InsertReplaceEdit {
22622                                    new_text: snippet.body.clone(),
22623                                    insert: lsp_range,
22624                                    replace: lsp_range,
22625                                },
22626                            )),
22627                            filter_text: Some(snippet.body.clone()),
22628                            sort_text: Some(char::MAX.to_string()),
22629                            ..lsp::CompletionItem::default()
22630                        }),
22631                        lsp_defaults: None,
22632                    },
22633                    label: CodeLabel {
22634                        text: matching_prefix.clone(),
22635                        runs: Vec::new(),
22636                        filter_range: 0..matching_prefix.len(),
22637                    },
22638                    icon_path: None,
22639                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22640                        single_line: snippet.name.clone().into(),
22641                        plain_text: snippet
22642                            .description
22643                            .clone()
22644                            .map(|description| description.into()),
22645                    }),
22646                    insert_text_mode: None,
22647                    confirm: None,
22648                })
22649            }))
22650        }
22651
22652        Ok(CompletionResponse {
22653            completions,
22654            display_options: CompletionDisplayOptions::default(),
22655            is_incomplete,
22656        })
22657    })
22658}
22659
22660impl CompletionProvider for Entity<Project> {
22661    fn completions(
22662        &self,
22663        _excerpt_id: ExcerptId,
22664        buffer: &Entity<Buffer>,
22665        buffer_position: text::Anchor,
22666        options: CompletionContext,
22667        _window: &mut Window,
22668        cx: &mut Context<Editor>,
22669    ) -> Task<Result<Vec<CompletionResponse>>> {
22670        self.update(cx, |project, cx| {
22671            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22672            let project_completions = project.completions(buffer, buffer_position, options, cx);
22673            cx.background_spawn(async move {
22674                let mut responses = project_completions.await?;
22675                let snippets = snippets.await?;
22676                if !snippets.completions.is_empty() {
22677                    responses.push(snippets);
22678                }
22679                Ok(responses)
22680            })
22681        })
22682    }
22683
22684    fn resolve_completions(
22685        &self,
22686        buffer: Entity<Buffer>,
22687        completion_indices: Vec<usize>,
22688        completions: Rc<RefCell<Box<[Completion]>>>,
22689        cx: &mut Context<Editor>,
22690    ) -> Task<Result<bool>> {
22691        self.update(cx, |project, cx| {
22692            project.lsp_store().update(cx, |lsp_store, cx| {
22693                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22694            })
22695        })
22696    }
22697
22698    fn apply_additional_edits_for_completion(
22699        &self,
22700        buffer: Entity<Buffer>,
22701        completions: Rc<RefCell<Box<[Completion]>>>,
22702        completion_index: usize,
22703        push_to_history: bool,
22704        cx: &mut Context<Editor>,
22705    ) -> Task<Result<Option<language::Transaction>>> {
22706        self.update(cx, |project, cx| {
22707            project.lsp_store().update(cx, |lsp_store, cx| {
22708                lsp_store.apply_additional_edits_for_completion(
22709                    buffer,
22710                    completions,
22711                    completion_index,
22712                    push_to_history,
22713                    cx,
22714                )
22715            })
22716        })
22717    }
22718
22719    fn is_completion_trigger(
22720        &self,
22721        buffer: &Entity<Buffer>,
22722        position: language::Anchor,
22723        text: &str,
22724        trigger_in_words: bool,
22725        menu_is_open: bool,
22726        cx: &mut Context<Editor>,
22727    ) -> bool {
22728        let mut chars = text.chars();
22729        let char = if let Some(char) = chars.next() {
22730            char
22731        } else {
22732            return false;
22733        };
22734        if chars.next().is_some() {
22735            return false;
22736        }
22737
22738        let buffer = buffer.read(cx);
22739        let snapshot = buffer.snapshot();
22740        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22741            return false;
22742        }
22743        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22744        if trigger_in_words && classifier.is_word(char) {
22745            return true;
22746        }
22747
22748        buffer.completion_triggers().contains(text)
22749    }
22750}
22751
22752impl SemanticsProvider for Entity<Project> {
22753    fn hover(
22754        &self,
22755        buffer: &Entity<Buffer>,
22756        position: text::Anchor,
22757        cx: &mut App,
22758    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22759        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22760    }
22761
22762    fn document_highlights(
22763        &self,
22764        buffer: &Entity<Buffer>,
22765        position: text::Anchor,
22766        cx: &mut App,
22767    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22768        Some(self.update(cx, |project, cx| {
22769            project.document_highlights(buffer, position, cx)
22770        }))
22771    }
22772
22773    fn definitions(
22774        &self,
22775        buffer: &Entity<Buffer>,
22776        position: text::Anchor,
22777        kind: GotoDefinitionKind,
22778        cx: &mut App,
22779    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22780        Some(self.update(cx, |project, cx| match kind {
22781            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22782            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22783            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22784            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22785        }))
22786    }
22787
22788    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22789        self.update(cx, |project, cx| {
22790            if project
22791                .active_debug_session(cx)
22792                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22793            {
22794                return true;
22795            }
22796
22797            buffer.update(cx, |buffer, cx| {
22798                project.any_language_server_supports_inlay_hints(buffer, cx)
22799            })
22800        })
22801    }
22802
22803    fn inline_values(
22804        &self,
22805        buffer_handle: Entity<Buffer>,
22806        range: Range<text::Anchor>,
22807        cx: &mut App,
22808    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22809        self.update(cx, |project, cx| {
22810            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22811
22812            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22813        })
22814    }
22815
22816    fn inlay_hints(
22817        &self,
22818        buffer_handle: Entity<Buffer>,
22819        range: Range<text::Anchor>,
22820        cx: &mut App,
22821    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22822        Some(self.update(cx, |project, cx| {
22823            project.inlay_hints(buffer_handle, range, cx)
22824        }))
22825    }
22826
22827    fn resolve_inlay_hint(
22828        &self,
22829        hint: InlayHint,
22830        buffer_handle: Entity<Buffer>,
22831        server_id: LanguageServerId,
22832        cx: &mut App,
22833    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22834        Some(self.update(cx, |project, cx| {
22835            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22836        }))
22837    }
22838
22839    fn range_for_rename(
22840        &self,
22841        buffer: &Entity<Buffer>,
22842        position: text::Anchor,
22843        cx: &mut App,
22844    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22845        Some(self.update(cx, |project, cx| {
22846            let buffer = buffer.clone();
22847            let task = project.prepare_rename(buffer.clone(), position, cx);
22848            cx.spawn(async move |_, cx| {
22849                Ok(match task.await? {
22850                    PrepareRenameResponse::Success(range) => Some(range),
22851                    PrepareRenameResponse::InvalidPosition => None,
22852                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22853                        // Fallback on using TreeSitter info to determine identifier range
22854                        buffer.read_with(cx, |buffer, _| {
22855                            let snapshot = buffer.snapshot();
22856                            let (range, kind) = snapshot.surrounding_word(position, false);
22857                            if kind != Some(CharKind::Word) {
22858                                return None;
22859                            }
22860                            Some(
22861                                snapshot.anchor_before(range.start)
22862                                    ..snapshot.anchor_after(range.end),
22863                            )
22864                        })?
22865                    }
22866                })
22867            })
22868        }))
22869    }
22870
22871    fn perform_rename(
22872        &self,
22873        buffer: &Entity<Buffer>,
22874        position: text::Anchor,
22875        new_name: String,
22876        cx: &mut App,
22877    ) -> Option<Task<Result<ProjectTransaction>>> {
22878        Some(self.update(cx, |project, cx| {
22879            project.perform_rename(buffer.clone(), position, new_name, cx)
22880        }))
22881    }
22882}
22883
22884fn inlay_hint_settings(
22885    location: Anchor,
22886    snapshot: &MultiBufferSnapshot,
22887    cx: &mut Context<Editor>,
22888) -> InlayHintSettings {
22889    let file = snapshot.file_at(location);
22890    let language = snapshot.language_at(location).map(|l| l.name());
22891    language_settings(language, file, cx).inlay_hints
22892}
22893
22894fn consume_contiguous_rows(
22895    contiguous_row_selections: &mut Vec<Selection<Point>>,
22896    selection: &Selection<Point>,
22897    display_map: &DisplaySnapshot,
22898    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22899) -> (MultiBufferRow, MultiBufferRow) {
22900    contiguous_row_selections.push(selection.clone());
22901    let start_row = starting_row(selection, display_map);
22902    let mut end_row = ending_row(selection, display_map);
22903
22904    while let Some(next_selection) = selections.peek() {
22905        if next_selection.start.row <= end_row.0 {
22906            end_row = ending_row(next_selection, display_map);
22907            contiguous_row_selections.push(selections.next().unwrap().clone());
22908        } else {
22909            break;
22910        }
22911    }
22912    (start_row, end_row)
22913}
22914
22915fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22916    if selection.start.column > 0 {
22917        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22918    } else {
22919        MultiBufferRow(selection.start.row)
22920    }
22921}
22922
22923fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22924    if next_selection.end.column > 0 || next_selection.is_empty() {
22925        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22926    } else {
22927        MultiBufferRow(next_selection.end.row)
22928    }
22929}
22930
22931impl EditorSnapshot {
22932    pub fn remote_selections_in_range<'a>(
22933        &'a self,
22934        range: &'a Range<Anchor>,
22935        collaboration_hub: &dyn CollaborationHub,
22936        cx: &'a App,
22937    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22938        let participant_names = collaboration_hub.user_names(cx);
22939        let participant_indices = collaboration_hub.user_participant_indices(cx);
22940        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22941        let collaborators_by_replica_id = collaborators_by_peer_id
22942            .values()
22943            .map(|collaborator| (collaborator.replica_id, collaborator))
22944            .collect::<HashMap<_, _>>();
22945        self.buffer_snapshot
22946            .selections_in_range(range, false)
22947            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22948                if replica_id == AGENT_REPLICA_ID {
22949                    Some(RemoteSelection {
22950                        replica_id,
22951                        selection,
22952                        cursor_shape,
22953                        line_mode,
22954                        collaborator_id: CollaboratorId::Agent,
22955                        user_name: Some("Agent".into()),
22956                        color: cx.theme().players().agent(),
22957                    })
22958                } else {
22959                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22960                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22961                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22962                    Some(RemoteSelection {
22963                        replica_id,
22964                        selection,
22965                        cursor_shape,
22966                        line_mode,
22967                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22968                        user_name,
22969                        color: if let Some(index) = participant_index {
22970                            cx.theme().players().color_for_participant(index.0)
22971                        } else {
22972                            cx.theme().players().absent()
22973                        },
22974                    })
22975                }
22976            })
22977    }
22978
22979    pub fn hunks_for_ranges(
22980        &self,
22981        ranges: impl IntoIterator<Item = Range<Point>>,
22982    ) -> Vec<MultiBufferDiffHunk> {
22983        let mut hunks = Vec::new();
22984        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22985            HashMap::default();
22986        for query_range in ranges {
22987            let query_rows =
22988                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22989            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22990                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22991            ) {
22992                // Include deleted hunks that are adjacent to the query range, because
22993                // otherwise they would be missed.
22994                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22995                if hunk.status().is_deleted() {
22996                    intersects_range |= hunk.row_range.start == query_rows.end;
22997                    intersects_range |= hunk.row_range.end == query_rows.start;
22998                }
22999                if intersects_range {
23000                    if !processed_buffer_rows
23001                        .entry(hunk.buffer_id)
23002                        .or_default()
23003                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23004                    {
23005                        continue;
23006                    }
23007                    hunks.push(hunk);
23008                }
23009            }
23010        }
23011
23012        hunks
23013    }
23014
23015    fn display_diff_hunks_for_rows<'a>(
23016        &'a self,
23017        display_rows: Range<DisplayRow>,
23018        folded_buffers: &'a HashSet<BufferId>,
23019    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23020        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23021        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23022
23023        self.buffer_snapshot
23024            .diff_hunks_in_range(buffer_start..buffer_end)
23025            .filter_map(|hunk| {
23026                if folded_buffers.contains(&hunk.buffer_id) {
23027                    return None;
23028                }
23029
23030                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23031                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23032
23033                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23034                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23035
23036                let display_hunk = if hunk_display_start.column() != 0 {
23037                    DisplayDiffHunk::Folded {
23038                        display_row: hunk_display_start.row(),
23039                    }
23040                } else {
23041                    let mut end_row = hunk_display_end.row();
23042                    if hunk_display_end.column() > 0 {
23043                        end_row.0 += 1;
23044                    }
23045                    let is_created_file = hunk.is_created_file();
23046                    DisplayDiffHunk::Unfolded {
23047                        status: hunk.status(),
23048                        diff_base_byte_range: hunk.diff_base_byte_range,
23049                        display_row_range: hunk_display_start.row()..end_row,
23050                        multi_buffer_range: Anchor::range_in_buffer(
23051                            hunk.excerpt_id,
23052                            hunk.buffer_id,
23053                            hunk.buffer_range,
23054                        ),
23055                        is_created_file,
23056                    }
23057                };
23058
23059                Some(display_hunk)
23060            })
23061    }
23062
23063    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23064        self.display_snapshot.buffer_snapshot.language_at(position)
23065    }
23066
23067    pub fn is_focused(&self) -> bool {
23068        self.is_focused
23069    }
23070
23071    pub fn placeholder_text(&self) -> Option<String> {
23072        self.placeholder_display_snapshot
23073            .as_ref()
23074            .map(|display_map| display_map.text())
23075    }
23076
23077    pub fn scroll_position(&self) -> gpui::Point<f32> {
23078        self.scroll_anchor.scroll_position(&self.display_snapshot)
23079    }
23080
23081    fn gutter_dimensions(
23082        &self,
23083        font_id: FontId,
23084        font_size: Pixels,
23085        max_line_number_width: Pixels,
23086        cx: &App,
23087    ) -> Option<GutterDimensions> {
23088        if !self.show_gutter {
23089            return None;
23090        }
23091
23092        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23093        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23094
23095        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23096            matches!(
23097                ProjectSettings::get_global(cx).git.git_gutter,
23098                Some(GitGutterSetting::TrackedFiles)
23099            )
23100        });
23101        let gutter_settings = EditorSettings::get_global(cx).gutter;
23102        let show_line_numbers = self
23103            .show_line_numbers
23104            .unwrap_or(gutter_settings.line_numbers);
23105        let line_gutter_width = if show_line_numbers {
23106            // Avoid flicker-like gutter resizes when the line number gains another digit by
23107            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23108            let min_width_for_number_on_gutter =
23109                ch_advance * gutter_settings.min_line_number_digits as f32;
23110            max_line_number_width.max(min_width_for_number_on_gutter)
23111        } else {
23112            0.0.into()
23113        };
23114
23115        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23116        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23117
23118        let git_blame_entries_width =
23119            self.git_blame_gutter_max_author_length
23120                .map(|max_author_length| {
23121                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23122                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23123
23124                    /// The number of characters to dedicate to gaps and margins.
23125                    const SPACING_WIDTH: usize = 4;
23126
23127                    let max_char_count = max_author_length.min(renderer.max_author_length())
23128                        + ::git::SHORT_SHA_LENGTH
23129                        + MAX_RELATIVE_TIMESTAMP.len()
23130                        + SPACING_WIDTH;
23131
23132                    ch_advance * max_char_count
23133                });
23134
23135        let is_singleton = self.buffer_snapshot.is_singleton();
23136
23137        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23138        left_padding += if !is_singleton {
23139            ch_width * 4.0
23140        } else if show_runnables || show_breakpoints {
23141            ch_width * 3.0
23142        } else if show_git_gutter && show_line_numbers {
23143            ch_width * 2.0
23144        } else if show_git_gutter || show_line_numbers {
23145            ch_width
23146        } else {
23147            px(0.)
23148        };
23149
23150        let shows_folds = is_singleton && gutter_settings.folds;
23151
23152        let right_padding = if shows_folds && show_line_numbers {
23153            ch_width * 4.0
23154        } else if shows_folds || (!is_singleton && show_line_numbers) {
23155            ch_width * 3.0
23156        } else if show_line_numbers {
23157            ch_width
23158        } else {
23159            px(0.)
23160        };
23161
23162        Some(GutterDimensions {
23163            left_padding,
23164            right_padding,
23165            width: line_gutter_width + left_padding + right_padding,
23166            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23167            git_blame_entries_width,
23168        })
23169    }
23170
23171    pub fn render_crease_toggle(
23172        &self,
23173        buffer_row: MultiBufferRow,
23174        row_contains_cursor: bool,
23175        editor: Entity<Editor>,
23176        window: &mut Window,
23177        cx: &mut App,
23178    ) -> Option<AnyElement> {
23179        let folded = self.is_line_folded(buffer_row);
23180        let mut is_foldable = false;
23181
23182        if let Some(crease) = self
23183            .crease_snapshot
23184            .query_row(buffer_row, &self.buffer_snapshot)
23185        {
23186            is_foldable = true;
23187            match crease {
23188                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23189                    if let Some(render_toggle) = render_toggle {
23190                        let toggle_callback =
23191                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23192                                if folded {
23193                                    editor.update(cx, |editor, cx| {
23194                                        editor.fold_at(buffer_row, window, cx)
23195                                    });
23196                                } else {
23197                                    editor.update(cx, |editor, cx| {
23198                                        editor.unfold_at(buffer_row, window, cx)
23199                                    });
23200                                }
23201                            });
23202                        return Some((render_toggle)(
23203                            buffer_row,
23204                            folded,
23205                            toggle_callback,
23206                            window,
23207                            cx,
23208                        ));
23209                    }
23210                }
23211            }
23212        }
23213
23214        is_foldable |= self.starts_indent(buffer_row);
23215
23216        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23217            Some(
23218                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23219                    .toggle_state(folded)
23220                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23221                        if folded {
23222                            this.unfold_at(buffer_row, window, cx);
23223                        } else {
23224                            this.fold_at(buffer_row, window, cx);
23225                        }
23226                    }))
23227                    .into_any_element(),
23228            )
23229        } else {
23230            None
23231        }
23232    }
23233
23234    pub fn render_crease_trailer(
23235        &self,
23236        buffer_row: MultiBufferRow,
23237        window: &mut Window,
23238        cx: &mut App,
23239    ) -> Option<AnyElement> {
23240        let folded = self.is_line_folded(buffer_row);
23241        if let Crease::Inline { render_trailer, .. } = self
23242            .crease_snapshot
23243            .query_row(buffer_row, &self.buffer_snapshot)?
23244        {
23245            let render_trailer = render_trailer.as_ref()?;
23246            Some(render_trailer(buffer_row, folded, window, cx))
23247        } else {
23248            None
23249        }
23250    }
23251}
23252
23253impl Deref for EditorSnapshot {
23254    type Target = DisplaySnapshot;
23255
23256    fn deref(&self) -> &Self::Target {
23257        &self.display_snapshot
23258    }
23259}
23260
23261#[derive(Clone, Debug, PartialEq, Eq)]
23262pub enum EditorEvent {
23263    InputIgnored {
23264        text: Arc<str>,
23265    },
23266    InputHandled {
23267        utf16_range_to_replace: Option<Range<isize>>,
23268        text: Arc<str>,
23269    },
23270    ExcerptsAdded {
23271        buffer: Entity<Buffer>,
23272        predecessor: ExcerptId,
23273        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23274    },
23275    ExcerptsRemoved {
23276        ids: Vec<ExcerptId>,
23277        removed_buffer_ids: Vec<BufferId>,
23278    },
23279    BufferFoldToggled {
23280        ids: Vec<ExcerptId>,
23281        folded: bool,
23282    },
23283    ExcerptsEdited {
23284        ids: Vec<ExcerptId>,
23285    },
23286    ExcerptsExpanded {
23287        ids: Vec<ExcerptId>,
23288    },
23289    BufferEdited,
23290    Edited {
23291        transaction_id: clock::Lamport,
23292    },
23293    Reparsed(BufferId),
23294    Focused,
23295    FocusedIn,
23296    Blurred,
23297    DirtyChanged,
23298    Saved,
23299    TitleChanged,
23300    SelectionsChanged {
23301        local: bool,
23302    },
23303    ScrollPositionChanged {
23304        local: bool,
23305        autoscroll: bool,
23306    },
23307    TransactionUndone {
23308        transaction_id: clock::Lamport,
23309    },
23310    TransactionBegun {
23311        transaction_id: clock::Lamport,
23312    },
23313    CursorShapeChanged,
23314    BreadcrumbsChanged,
23315    PushedToNavHistory {
23316        anchor: Anchor,
23317        is_deactivate: bool,
23318    },
23319}
23320
23321impl EventEmitter<EditorEvent> for Editor {}
23322
23323impl Focusable for Editor {
23324    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23325        self.focus_handle.clone()
23326    }
23327}
23328
23329impl Render for Editor {
23330    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23331        let settings = ThemeSettings::get_global(cx);
23332
23333        let mut text_style = match self.mode {
23334            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23335                color: cx.theme().colors().editor_foreground,
23336                font_family: settings.ui_font.family.clone(),
23337                font_features: settings.ui_font.features.clone(),
23338                font_fallbacks: settings.ui_font.fallbacks.clone(),
23339                font_size: rems(0.875).into(),
23340                font_weight: settings.ui_font.weight,
23341                line_height: relative(settings.buffer_line_height.value()),
23342                ..Default::default()
23343            },
23344            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23345                color: cx.theme().colors().editor_foreground,
23346                font_family: settings.buffer_font.family.clone(),
23347                font_features: settings.buffer_font.features.clone(),
23348                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23349                font_size: settings.buffer_font_size(cx).into(),
23350                font_weight: settings.buffer_font.weight,
23351                line_height: relative(settings.buffer_line_height.value()),
23352                ..Default::default()
23353            },
23354        };
23355        if let Some(text_style_refinement) = &self.text_style_refinement {
23356            text_style.refine(text_style_refinement)
23357        }
23358
23359        let background = match self.mode {
23360            EditorMode::SingleLine => cx.theme().system().transparent,
23361            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23362            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23363            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23364        };
23365
23366        EditorElement::new(
23367            &cx.entity(),
23368            EditorStyle {
23369                background,
23370                border: cx.theme().colors().border,
23371                local_player: cx.theme().players().local(),
23372                text: text_style,
23373                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23374                syntax: cx.theme().syntax().clone(),
23375                status: cx.theme().status().clone(),
23376                inlay_hints_style: make_inlay_hints_style(cx),
23377                edit_prediction_styles: make_suggestion_styles(cx),
23378                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23379                show_underlines: self.diagnostics_enabled(),
23380            },
23381        )
23382    }
23383}
23384
23385impl EntityInputHandler for Editor {
23386    fn text_for_range(
23387        &mut self,
23388        range_utf16: Range<usize>,
23389        adjusted_range: &mut Option<Range<usize>>,
23390        _: &mut Window,
23391        cx: &mut Context<Self>,
23392    ) -> Option<String> {
23393        let snapshot = self.buffer.read(cx).read(cx);
23394        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23395        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23396        if (start.0..end.0) != range_utf16 {
23397            adjusted_range.replace(start.0..end.0);
23398        }
23399        Some(snapshot.text_for_range(start..end).collect())
23400    }
23401
23402    fn selected_text_range(
23403        &mut self,
23404        ignore_disabled_input: bool,
23405        _: &mut Window,
23406        cx: &mut Context<Self>,
23407    ) -> Option<UTF16Selection> {
23408        // Prevent the IME menu from appearing when holding down an alphabetic key
23409        // while input is disabled.
23410        if !ignore_disabled_input && !self.input_enabled {
23411            return None;
23412        }
23413
23414        let selection = self.selections.newest::<OffsetUtf16>(cx);
23415        let range = selection.range();
23416
23417        Some(UTF16Selection {
23418            range: range.start.0..range.end.0,
23419            reversed: selection.reversed,
23420        })
23421    }
23422
23423    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23424        let snapshot = self.buffer.read(cx).read(cx);
23425        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23426        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23427    }
23428
23429    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23430        self.clear_highlights::<InputComposition>(cx);
23431        self.ime_transaction.take();
23432    }
23433
23434    fn replace_text_in_range(
23435        &mut self,
23436        range_utf16: Option<Range<usize>>,
23437        text: &str,
23438        window: &mut Window,
23439        cx: &mut Context<Self>,
23440    ) {
23441        if !self.input_enabled {
23442            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23443            return;
23444        }
23445
23446        self.transact(window, cx, |this, window, cx| {
23447            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23448                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23449                Some(this.selection_replacement_ranges(range_utf16, cx))
23450            } else {
23451                this.marked_text_ranges(cx)
23452            };
23453
23454            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23455                let newest_selection_id = this.selections.newest_anchor().id;
23456                this.selections
23457                    .all::<OffsetUtf16>(cx)
23458                    .iter()
23459                    .zip(ranges_to_replace.iter())
23460                    .find_map(|(selection, range)| {
23461                        if selection.id == newest_selection_id {
23462                            Some(
23463                                (range.start.0 as isize - selection.head().0 as isize)
23464                                    ..(range.end.0 as isize - selection.head().0 as isize),
23465                            )
23466                        } else {
23467                            None
23468                        }
23469                    })
23470            });
23471
23472            cx.emit(EditorEvent::InputHandled {
23473                utf16_range_to_replace: range_to_replace,
23474                text: text.into(),
23475            });
23476
23477            if let Some(new_selected_ranges) = new_selected_ranges {
23478                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23479                    selections.select_ranges(new_selected_ranges)
23480                });
23481                this.backspace(&Default::default(), window, cx);
23482            }
23483
23484            this.handle_input(text, window, cx);
23485        });
23486
23487        if let Some(transaction) = self.ime_transaction {
23488            self.buffer.update(cx, |buffer, cx| {
23489                buffer.group_until_transaction(transaction, cx);
23490            });
23491        }
23492
23493        self.unmark_text(window, cx);
23494    }
23495
23496    fn replace_and_mark_text_in_range(
23497        &mut self,
23498        range_utf16: Option<Range<usize>>,
23499        text: &str,
23500        new_selected_range_utf16: Option<Range<usize>>,
23501        window: &mut Window,
23502        cx: &mut Context<Self>,
23503    ) {
23504        if !self.input_enabled {
23505            return;
23506        }
23507
23508        let transaction = self.transact(window, cx, |this, window, cx| {
23509            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23510                let snapshot = this.buffer.read(cx).read(cx);
23511                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23512                    for marked_range in &mut marked_ranges {
23513                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23514                        marked_range.start.0 += relative_range_utf16.start;
23515                        marked_range.start =
23516                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23517                        marked_range.end =
23518                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23519                    }
23520                }
23521                Some(marked_ranges)
23522            } else if let Some(range_utf16) = range_utf16 {
23523                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23524                Some(this.selection_replacement_ranges(range_utf16, cx))
23525            } else {
23526                None
23527            };
23528
23529            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23530                let newest_selection_id = this.selections.newest_anchor().id;
23531                this.selections
23532                    .all::<OffsetUtf16>(cx)
23533                    .iter()
23534                    .zip(ranges_to_replace.iter())
23535                    .find_map(|(selection, range)| {
23536                        if selection.id == newest_selection_id {
23537                            Some(
23538                                (range.start.0 as isize - selection.head().0 as isize)
23539                                    ..(range.end.0 as isize - selection.head().0 as isize),
23540                            )
23541                        } else {
23542                            None
23543                        }
23544                    })
23545            });
23546
23547            cx.emit(EditorEvent::InputHandled {
23548                utf16_range_to_replace: range_to_replace,
23549                text: text.into(),
23550            });
23551
23552            if let Some(ranges) = ranges_to_replace {
23553                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23554                    s.select_ranges(ranges)
23555                });
23556            }
23557
23558            let marked_ranges = {
23559                let snapshot = this.buffer.read(cx).read(cx);
23560                this.selections
23561                    .disjoint_anchors()
23562                    .iter()
23563                    .map(|selection| {
23564                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23565                    })
23566                    .collect::<Vec<_>>()
23567            };
23568
23569            if text.is_empty() {
23570                this.unmark_text(window, cx);
23571            } else {
23572                this.highlight_text::<InputComposition>(
23573                    marked_ranges.clone(),
23574                    HighlightStyle {
23575                        underline: Some(UnderlineStyle {
23576                            thickness: px(1.),
23577                            color: None,
23578                            wavy: false,
23579                        }),
23580                        ..Default::default()
23581                    },
23582                    cx,
23583                );
23584            }
23585
23586            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23587            let use_autoclose = this.use_autoclose;
23588            let use_auto_surround = this.use_auto_surround;
23589            this.set_use_autoclose(false);
23590            this.set_use_auto_surround(false);
23591            this.handle_input(text, window, cx);
23592            this.set_use_autoclose(use_autoclose);
23593            this.set_use_auto_surround(use_auto_surround);
23594
23595            if let Some(new_selected_range) = new_selected_range_utf16 {
23596                let snapshot = this.buffer.read(cx).read(cx);
23597                let new_selected_ranges = marked_ranges
23598                    .into_iter()
23599                    .map(|marked_range| {
23600                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23601                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23602                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23603                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23604                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23605                    })
23606                    .collect::<Vec<_>>();
23607
23608                drop(snapshot);
23609                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23610                    selections.select_ranges(new_selected_ranges)
23611                });
23612            }
23613        });
23614
23615        self.ime_transaction = self.ime_transaction.or(transaction);
23616        if let Some(transaction) = self.ime_transaction {
23617            self.buffer.update(cx, |buffer, cx| {
23618                buffer.group_until_transaction(transaction, cx);
23619            });
23620        }
23621
23622        if self.text_highlights::<InputComposition>(cx).is_none() {
23623            self.ime_transaction.take();
23624        }
23625    }
23626
23627    fn bounds_for_range(
23628        &mut self,
23629        range_utf16: Range<usize>,
23630        element_bounds: gpui::Bounds<Pixels>,
23631        window: &mut Window,
23632        cx: &mut Context<Self>,
23633    ) -> Option<gpui::Bounds<Pixels>> {
23634        let text_layout_details = self.text_layout_details(window);
23635        let CharacterDimensions {
23636            em_width,
23637            em_advance,
23638            line_height,
23639        } = self.character_dimensions(window);
23640
23641        let snapshot = self.snapshot(window, cx);
23642        let scroll_position = snapshot.scroll_position();
23643        let scroll_left = scroll_position.x * em_advance;
23644
23645        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23646        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23647            + self.gutter_dimensions.full_width();
23648        let y = line_height * (start.row().as_f32() - scroll_position.y);
23649
23650        Some(Bounds {
23651            origin: element_bounds.origin + point(x, y),
23652            size: size(em_width, line_height),
23653        })
23654    }
23655
23656    fn character_index_for_point(
23657        &mut self,
23658        point: gpui::Point<Pixels>,
23659        _window: &mut Window,
23660        _cx: &mut Context<Self>,
23661    ) -> Option<usize> {
23662        let position_map = self.last_position_map.as_ref()?;
23663        if !position_map.text_hitbox.contains(&point) {
23664            return None;
23665        }
23666        let display_point = position_map.point_for_position(point).previous_valid;
23667        let anchor = position_map
23668            .snapshot
23669            .display_point_to_anchor(display_point, Bias::Left);
23670        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23671        Some(utf16_offset.0)
23672    }
23673}
23674
23675trait SelectionExt {
23676    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23677    fn spanned_rows(
23678        &self,
23679        include_end_if_at_line_start: bool,
23680        map: &DisplaySnapshot,
23681    ) -> Range<MultiBufferRow>;
23682}
23683
23684impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23685    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23686        let start = self
23687            .start
23688            .to_point(&map.buffer_snapshot)
23689            .to_display_point(map);
23690        let end = self
23691            .end
23692            .to_point(&map.buffer_snapshot)
23693            .to_display_point(map);
23694        if self.reversed {
23695            end..start
23696        } else {
23697            start..end
23698        }
23699    }
23700
23701    fn spanned_rows(
23702        &self,
23703        include_end_if_at_line_start: bool,
23704        map: &DisplaySnapshot,
23705    ) -> Range<MultiBufferRow> {
23706        let start = self.start.to_point(&map.buffer_snapshot);
23707        let mut end = self.end.to_point(&map.buffer_snapshot);
23708        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23709            end.row -= 1;
23710        }
23711
23712        let buffer_start = map.prev_line_boundary(start).0;
23713        let buffer_end = map.next_line_boundary(end).0;
23714        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23715    }
23716}
23717
23718impl<T: InvalidationRegion> InvalidationStack<T> {
23719    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23720    where
23721        S: Clone + ToOffset,
23722    {
23723        while let Some(region) = self.last() {
23724            let all_selections_inside_invalidation_ranges =
23725                if selections.len() == region.ranges().len() {
23726                    selections
23727                        .iter()
23728                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23729                        .all(|(selection, invalidation_range)| {
23730                            let head = selection.head().to_offset(buffer);
23731                            invalidation_range.start <= head && invalidation_range.end >= head
23732                        })
23733                } else {
23734                    false
23735                };
23736
23737            if all_selections_inside_invalidation_ranges {
23738                break;
23739            } else {
23740                self.pop();
23741            }
23742        }
23743    }
23744}
23745
23746impl<T> Default for InvalidationStack<T> {
23747    fn default() -> Self {
23748        Self(Default::default())
23749    }
23750}
23751
23752impl<T> Deref for InvalidationStack<T> {
23753    type Target = Vec<T>;
23754
23755    fn deref(&self) -> &Self::Target {
23756        &self.0
23757    }
23758}
23759
23760impl<T> DerefMut for InvalidationStack<T> {
23761    fn deref_mut(&mut self) -> &mut Self::Target {
23762        &mut self.0
23763    }
23764}
23765
23766impl InvalidationRegion for SnippetState {
23767    fn ranges(&self) -> &[Range<Anchor>] {
23768        &self.ranges[self.active_index]
23769    }
23770}
23771
23772fn edit_prediction_edit_text(
23773    current_snapshot: &BufferSnapshot,
23774    edits: &[(Range<Anchor>, String)],
23775    edit_preview: &EditPreview,
23776    include_deletions: bool,
23777    cx: &App,
23778) -> HighlightedText {
23779    let edits = edits
23780        .iter()
23781        .map(|(anchor, text)| {
23782            (
23783                anchor.start.text_anchor..anchor.end.text_anchor,
23784                text.clone(),
23785            )
23786        })
23787        .collect::<Vec<_>>();
23788
23789    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23790}
23791
23792fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23793    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23794    // Just show the raw edit text with basic styling
23795    let mut text = String::new();
23796    let mut highlights = Vec::new();
23797
23798    let insertion_highlight_style = HighlightStyle {
23799        color: Some(cx.theme().colors().text),
23800        ..Default::default()
23801    };
23802
23803    for (_, edit_text) in edits {
23804        let start_offset = text.len();
23805        text.push_str(edit_text);
23806        let end_offset = text.len();
23807
23808        if start_offset < end_offset {
23809            highlights.push((start_offset..end_offset, insertion_highlight_style));
23810        }
23811    }
23812
23813    HighlightedText {
23814        text: text.into(),
23815        highlights,
23816    }
23817}
23818
23819pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23820    match severity {
23821        lsp::DiagnosticSeverity::ERROR => colors.error,
23822        lsp::DiagnosticSeverity::WARNING => colors.warning,
23823        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23824        lsp::DiagnosticSeverity::HINT => colors.info,
23825        _ => colors.ignored,
23826    }
23827}
23828
23829pub fn styled_runs_for_code_label<'a>(
23830    label: &'a CodeLabel,
23831    syntax_theme: &'a theme::SyntaxTheme,
23832) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23833    let fade_out = HighlightStyle {
23834        fade_out: Some(0.35),
23835        ..Default::default()
23836    };
23837
23838    let mut prev_end = label.filter_range.end;
23839    label
23840        .runs
23841        .iter()
23842        .enumerate()
23843        .flat_map(move |(ix, (range, highlight_id))| {
23844            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23845                style
23846            } else {
23847                return Default::default();
23848            };
23849            let muted_style = style.highlight(fade_out);
23850
23851            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23852            if range.start >= label.filter_range.end {
23853                if range.start > prev_end {
23854                    runs.push((prev_end..range.start, fade_out));
23855                }
23856                runs.push((range.clone(), muted_style));
23857            } else if range.end <= label.filter_range.end {
23858                runs.push((range.clone(), style));
23859            } else {
23860                runs.push((range.start..label.filter_range.end, style));
23861                runs.push((label.filter_range.end..range.end, muted_style));
23862            }
23863            prev_end = cmp::max(prev_end, range.end);
23864
23865            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23866                runs.push((prev_end..label.text.len(), fade_out));
23867            }
23868
23869            runs
23870        })
23871}
23872
23873pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23874    let mut prev_index = 0;
23875    let mut prev_codepoint: Option<char> = None;
23876    text.char_indices()
23877        .chain([(text.len(), '\0')])
23878        .filter_map(move |(index, codepoint)| {
23879            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23880            let is_boundary = index == text.len()
23881                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23882                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23883            if is_boundary {
23884                let chunk = &text[prev_index..index];
23885                prev_index = index;
23886                Some(chunk)
23887            } else {
23888                None
23889            }
23890        })
23891}
23892
23893pub trait RangeToAnchorExt: Sized {
23894    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23895
23896    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23897        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23898        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23899    }
23900}
23901
23902impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23903    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23904        let start_offset = self.start.to_offset(snapshot);
23905        let end_offset = self.end.to_offset(snapshot);
23906        if start_offset == end_offset {
23907            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23908        } else {
23909            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23910        }
23911    }
23912}
23913
23914pub trait RowExt {
23915    fn as_f32(&self) -> f32;
23916
23917    fn next_row(&self) -> Self;
23918
23919    fn previous_row(&self) -> Self;
23920
23921    fn minus(&self, other: Self) -> u32;
23922}
23923
23924impl RowExt for DisplayRow {
23925    fn as_f32(&self) -> f32 {
23926        self.0 as f32
23927    }
23928
23929    fn next_row(&self) -> Self {
23930        Self(self.0 + 1)
23931    }
23932
23933    fn previous_row(&self) -> Self {
23934        Self(self.0.saturating_sub(1))
23935    }
23936
23937    fn minus(&self, other: Self) -> u32 {
23938        self.0 - other.0
23939    }
23940}
23941
23942impl RowExt for MultiBufferRow {
23943    fn as_f32(&self) -> f32 {
23944        self.0 as f32
23945    }
23946
23947    fn next_row(&self) -> Self {
23948        Self(self.0 + 1)
23949    }
23950
23951    fn previous_row(&self) -> Self {
23952        Self(self.0.saturating_sub(1))
23953    }
23954
23955    fn minus(&self, other: Self) -> u32 {
23956        self.0 - other.0
23957    }
23958}
23959
23960trait RowRangeExt {
23961    type Row;
23962
23963    fn len(&self) -> usize;
23964
23965    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23966}
23967
23968impl RowRangeExt for Range<MultiBufferRow> {
23969    type Row = MultiBufferRow;
23970
23971    fn len(&self) -> usize {
23972        (self.end.0 - self.start.0) as usize
23973    }
23974
23975    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23976        (self.start.0..self.end.0).map(MultiBufferRow)
23977    }
23978}
23979
23980impl RowRangeExt for Range<DisplayRow> {
23981    type Row = DisplayRow;
23982
23983    fn len(&self) -> usize {
23984        (self.end.0 - self.start.0) as usize
23985    }
23986
23987    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23988        (self.start.0..self.end.0).map(DisplayRow)
23989    }
23990}
23991
23992/// If select range has more than one line, we
23993/// just point the cursor to range.start.
23994fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23995    if range.start.row == range.end.row {
23996        range
23997    } else {
23998        range.start..range.start
23999    }
24000}
24001pub struct KillRing(ClipboardItem);
24002impl Global for KillRing {}
24003
24004const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24005
24006enum BreakpointPromptEditAction {
24007    Log,
24008    Condition,
24009    HitCondition,
24010}
24011
24012struct BreakpointPromptEditor {
24013    pub(crate) prompt: Entity<Editor>,
24014    editor: WeakEntity<Editor>,
24015    breakpoint_anchor: Anchor,
24016    breakpoint: Breakpoint,
24017    edit_action: BreakpointPromptEditAction,
24018    block_ids: HashSet<CustomBlockId>,
24019    editor_margins: Arc<Mutex<EditorMargins>>,
24020    _subscriptions: Vec<Subscription>,
24021}
24022
24023impl BreakpointPromptEditor {
24024    const MAX_LINES: u8 = 4;
24025
24026    fn new(
24027        editor: WeakEntity<Editor>,
24028        breakpoint_anchor: Anchor,
24029        breakpoint: Breakpoint,
24030        edit_action: BreakpointPromptEditAction,
24031        window: &mut Window,
24032        cx: &mut Context<Self>,
24033    ) -> Self {
24034        let base_text = match edit_action {
24035            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24036            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24037            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24038        }
24039        .map(|msg| msg.to_string())
24040        .unwrap_or_default();
24041
24042        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24043        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24044
24045        let prompt = cx.new(|cx| {
24046            let mut prompt = Editor::new(
24047                EditorMode::AutoHeight {
24048                    min_lines: 1,
24049                    max_lines: Some(Self::MAX_LINES as usize),
24050                },
24051                buffer,
24052                None,
24053                window,
24054                cx,
24055            );
24056            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24057            prompt.set_show_cursor_when_unfocused(false, cx);
24058            prompt.set_placeholder_text(
24059                match edit_action {
24060                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24061                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24062                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24063                },
24064                window,
24065                cx,
24066            );
24067
24068            prompt
24069        });
24070
24071        Self {
24072            prompt,
24073            editor,
24074            breakpoint_anchor,
24075            breakpoint,
24076            edit_action,
24077            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24078            block_ids: Default::default(),
24079            _subscriptions: vec![],
24080        }
24081    }
24082
24083    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24084        self.block_ids.extend(block_ids)
24085    }
24086
24087    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24088        if let Some(editor) = self.editor.upgrade() {
24089            let message = self
24090                .prompt
24091                .read(cx)
24092                .buffer
24093                .read(cx)
24094                .as_singleton()
24095                .expect("A multi buffer in breakpoint prompt isn't possible")
24096                .read(cx)
24097                .as_rope()
24098                .to_string();
24099
24100            editor.update(cx, |editor, cx| {
24101                editor.edit_breakpoint_at_anchor(
24102                    self.breakpoint_anchor,
24103                    self.breakpoint.clone(),
24104                    match self.edit_action {
24105                        BreakpointPromptEditAction::Log => {
24106                            BreakpointEditAction::EditLogMessage(message.into())
24107                        }
24108                        BreakpointPromptEditAction::Condition => {
24109                            BreakpointEditAction::EditCondition(message.into())
24110                        }
24111                        BreakpointPromptEditAction::HitCondition => {
24112                            BreakpointEditAction::EditHitCondition(message.into())
24113                        }
24114                    },
24115                    cx,
24116                );
24117
24118                editor.remove_blocks(self.block_ids.clone(), None, cx);
24119                cx.focus_self(window);
24120            });
24121        }
24122    }
24123
24124    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24125        self.editor
24126            .update(cx, |editor, cx| {
24127                editor.remove_blocks(self.block_ids.clone(), None, cx);
24128                window.focus(&editor.focus_handle);
24129            })
24130            .log_err();
24131    }
24132
24133    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24134        let settings = ThemeSettings::get_global(cx);
24135        let text_style = TextStyle {
24136            color: if self.prompt.read(cx).read_only(cx) {
24137                cx.theme().colors().text_disabled
24138            } else {
24139                cx.theme().colors().text
24140            },
24141            font_family: settings.buffer_font.family.clone(),
24142            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24143            font_size: settings.buffer_font_size(cx).into(),
24144            font_weight: settings.buffer_font.weight,
24145            line_height: relative(settings.buffer_line_height.value()),
24146            ..Default::default()
24147        };
24148        EditorElement::new(
24149            &self.prompt,
24150            EditorStyle {
24151                background: cx.theme().colors().editor_background,
24152                local_player: cx.theme().players().local(),
24153                text: text_style,
24154                ..Default::default()
24155            },
24156        )
24157    }
24158}
24159
24160impl Render for BreakpointPromptEditor {
24161    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24162        let editor_margins = *self.editor_margins.lock();
24163        let gutter_dimensions = editor_margins.gutter;
24164        h_flex()
24165            .key_context("Editor")
24166            .bg(cx.theme().colors().editor_background)
24167            .border_y_1()
24168            .border_color(cx.theme().status().info_border)
24169            .size_full()
24170            .py(window.line_height() / 2.5)
24171            .on_action(cx.listener(Self::confirm))
24172            .on_action(cx.listener(Self::cancel))
24173            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24174            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24175    }
24176}
24177
24178impl Focusable for BreakpointPromptEditor {
24179    fn focus_handle(&self, cx: &App) -> FocusHandle {
24180        self.prompt.focus_handle(cx)
24181    }
24182}
24183
24184fn all_edits_insertions_or_deletions(
24185    edits: &Vec<(Range<Anchor>, String)>,
24186    snapshot: &MultiBufferSnapshot,
24187) -> bool {
24188    let mut all_insertions = true;
24189    let mut all_deletions = true;
24190
24191    for (range, new_text) in edits.iter() {
24192        let range_is_empty = range.to_offset(snapshot).is_empty();
24193        let text_is_empty = new_text.is_empty();
24194
24195        if range_is_empty != text_is_empty {
24196            if range_is_empty {
24197                all_deletions = false;
24198            } else {
24199                all_insertions = false;
24200            }
24201        } else {
24202            return false;
24203        }
24204
24205        if !all_insertions && !all_deletions {
24206            return false;
24207        }
24208    }
24209    all_insertions || all_deletions
24210}
24211
24212struct MissingEditPredictionKeybindingTooltip;
24213
24214impl Render for MissingEditPredictionKeybindingTooltip {
24215    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24216        ui::tooltip_container(window, cx, |container, _, cx| {
24217            container
24218                .flex_shrink_0()
24219                .max_w_80()
24220                .min_h(rems_from_px(124.))
24221                .justify_between()
24222                .child(
24223                    v_flex()
24224                        .flex_1()
24225                        .text_ui_sm(cx)
24226                        .child(Label::new("Conflict with Accept Keybinding"))
24227                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24228                )
24229                .child(
24230                    h_flex()
24231                        .pb_1()
24232                        .gap_1()
24233                        .items_end()
24234                        .w_full()
24235                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24236                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24237                        }))
24238                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24239                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24240                        })),
24241                )
24242        })
24243    }
24244}
24245
24246#[derive(Debug, Clone, Copy, PartialEq)]
24247pub struct LineHighlight {
24248    pub background: Background,
24249    pub border: Option<gpui::Hsla>,
24250    pub include_gutter: bool,
24251    pub type_id: Option<TypeId>,
24252}
24253
24254struct LineManipulationResult {
24255    pub new_text: String,
24256    pub line_count_before: usize,
24257    pub line_count_after: usize,
24258}
24259
24260fn render_diff_hunk_controls(
24261    row: u32,
24262    status: &DiffHunkStatus,
24263    hunk_range: Range<Anchor>,
24264    is_created_file: bool,
24265    line_height: Pixels,
24266    editor: &Entity<Editor>,
24267    _window: &mut Window,
24268    cx: &mut App,
24269) -> AnyElement {
24270    h_flex()
24271        .h(line_height)
24272        .mr_1()
24273        .gap_1()
24274        .px_0p5()
24275        .pb_1()
24276        .border_x_1()
24277        .border_b_1()
24278        .border_color(cx.theme().colors().border_variant)
24279        .rounded_b_lg()
24280        .bg(cx.theme().colors().editor_background)
24281        .gap_1()
24282        .block_mouse_except_scroll()
24283        .shadow_md()
24284        .child(if status.has_secondary_hunk() {
24285            Button::new(("stage", row as u64), "Stage")
24286                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24287                .tooltip({
24288                    let focus_handle = editor.focus_handle(cx);
24289                    move |window, cx| {
24290                        Tooltip::for_action_in(
24291                            "Stage Hunk",
24292                            &::git::ToggleStaged,
24293                            &focus_handle,
24294                            window,
24295                            cx,
24296                        )
24297                    }
24298                })
24299                .on_click({
24300                    let editor = editor.clone();
24301                    move |_event, _window, cx| {
24302                        editor.update(cx, |editor, cx| {
24303                            editor.stage_or_unstage_diff_hunks(
24304                                true,
24305                                vec![hunk_range.start..hunk_range.start],
24306                                cx,
24307                            );
24308                        });
24309                    }
24310                })
24311        } else {
24312            Button::new(("unstage", row as u64), "Unstage")
24313                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24314                .tooltip({
24315                    let focus_handle = editor.focus_handle(cx);
24316                    move |window, cx| {
24317                        Tooltip::for_action_in(
24318                            "Unstage Hunk",
24319                            &::git::ToggleStaged,
24320                            &focus_handle,
24321                            window,
24322                            cx,
24323                        )
24324                    }
24325                })
24326                .on_click({
24327                    let editor = editor.clone();
24328                    move |_event, _window, cx| {
24329                        editor.update(cx, |editor, cx| {
24330                            editor.stage_or_unstage_diff_hunks(
24331                                false,
24332                                vec![hunk_range.start..hunk_range.start],
24333                                cx,
24334                            );
24335                        });
24336                    }
24337                })
24338        })
24339        .child(
24340            Button::new(("restore", row as u64), "Restore")
24341                .tooltip({
24342                    let focus_handle = editor.focus_handle(cx);
24343                    move |window, cx| {
24344                        Tooltip::for_action_in(
24345                            "Restore Hunk",
24346                            &::git::Restore,
24347                            &focus_handle,
24348                            window,
24349                            cx,
24350                        )
24351                    }
24352                })
24353                .on_click({
24354                    let editor = editor.clone();
24355                    move |_event, window, cx| {
24356                        editor.update(cx, |editor, cx| {
24357                            let snapshot = editor.snapshot(window, cx);
24358                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24359                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24360                        });
24361                    }
24362                })
24363                .disabled(is_created_file),
24364        )
24365        .when(
24366            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24367            |el| {
24368                el.child(
24369                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24370                        .shape(IconButtonShape::Square)
24371                        .icon_size(IconSize::Small)
24372                        // .disabled(!has_multiple_hunks)
24373                        .tooltip({
24374                            let focus_handle = editor.focus_handle(cx);
24375                            move |window, cx| {
24376                                Tooltip::for_action_in(
24377                                    "Next Hunk",
24378                                    &GoToHunk,
24379                                    &focus_handle,
24380                                    window,
24381                                    cx,
24382                                )
24383                            }
24384                        })
24385                        .on_click({
24386                            let editor = editor.clone();
24387                            move |_event, window, cx| {
24388                                editor.update(cx, |editor, cx| {
24389                                    let snapshot = editor.snapshot(window, cx);
24390                                    let position =
24391                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24392                                    editor.go_to_hunk_before_or_after_position(
24393                                        &snapshot,
24394                                        position,
24395                                        Direction::Next,
24396                                        window,
24397                                        cx,
24398                                    );
24399                                    editor.expand_selected_diff_hunks(cx);
24400                                });
24401                            }
24402                        }),
24403                )
24404                .child(
24405                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24406                        .shape(IconButtonShape::Square)
24407                        .icon_size(IconSize::Small)
24408                        // .disabled(!has_multiple_hunks)
24409                        .tooltip({
24410                            let focus_handle = editor.focus_handle(cx);
24411                            move |window, cx| {
24412                                Tooltip::for_action_in(
24413                                    "Previous Hunk",
24414                                    &GoToPreviousHunk,
24415                                    &focus_handle,
24416                                    window,
24417                                    cx,
24418                                )
24419                            }
24420                        })
24421                        .on_click({
24422                            let editor = editor.clone();
24423                            move |_event, window, cx| {
24424                                editor.update(cx, |editor, cx| {
24425                                    let snapshot = editor.snapshot(window, cx);
24426                                    let point =
24427                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24428                                    editor.go_to_hunk_before_or_after_position(
24429                                        &snapshot,
24430                                        point,
24431                                        Direction::Prev,
24432                                        window,
24433                                        cx,
24434                                    );
24435                                    editor.expand_selected_diff_hunks(cx);
24436                                });
24437                            }
24438                        }),
24439                )
24440            },
24441        )
24442        .into_any_element()
24443}
24444
24445pub fn multibuffer_context_lines(cx: &App) -> u32 {
24446    EditorSettings::try_get(cx)
24447        .map(|settings| settings.excerpt_context_lines)
24448        .unwrap_or(2)
24449        .min(32)
24450}