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    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint,
  152    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectPath,
  153    ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{
  164        DiagnosticSeverity, GitGutterSetting, GoToDiagnosticSeverityFilter, ProjectSettings,
  165    },
  166};
  167use rand::seq::SliceRandom;
  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, containing_range)) = buffer.syntax_ancestor(new_range.clone())
14992                {
14993                    new_range = match containing_range {
14994                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14995                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14996                    };
14997                    if !node.is_named() {
14998                        continue;
14999                    }
15000                    if !display_map.intersects_fold(new_range.start)
15001                        && !display_map.intersects_fold(new_range.end)
15002                    {
15003                        break;
15004                    }
15005                }
15006
15007                selected_larger_node |= new_range != old_range;
15008                Selection {
15009                    id: selection.id,
15010                    start: new_range.start,
15011                    end: new_range.end,
15012                    goal: SelectionGoal::None,
15013                    reversed: selection.reversed,
15014                }
15015            })
15016            .collect::<Vec<_>>();
15017
15018        if !selected_larger_node {
15019            return; // don't put this call in the history
15020        }
15021
15022        // scroll based on transformation done to the last selection created by the user
15023        let (last_old, last_new) = old_selections
15024            .last()
15025            .zip(new_selections.last().cloned())
15026            .expect("old_selections isn't empty");
15027
15028        // revert selection
15029        let is_selection_reversed = {
15030            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15031            new_selections.last_mut().expect("checked above").reversed =
15032                should_newest_selection_be_reversed;
15033            should_newest_selection_be_reversed
15034        };
15035
15036        if selected_larger_node {
15037            self.select_syntax_node_history.disable_clearing = true;
15038            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15039                s.select(new_selections.clone());
15040            });
15041            self.select_syntax_node_history.disable_clearing = false;
15042        }
15043
15044        let start_row = last_new.start.to_display_point(&display_map).row().0;
15045        let end_row = last_new.end.to_display_point(&display_map).row().0;
15046        let selection_height = end_row - start_row + 1;
15047        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15048
15049        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15050        let scroll_behavior = if fits_on_the_screen {
15051            self.request_autoscroll(Autoscroll::fit(), cx);
15052            SelectSyntaxNodeScrollBehavior::FitSelection
15053        } else if is_selection_reversed {
15054            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15055            SelectSyntaxNodeScrollBehavior::CursorTop
15056        } else {
15057            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15058            SelectSyntaxNodeScrollBehavior::CursorBottom
15059        };
15060
15061        self.select_syntax_node_history.push((
15062            old_selections,
15063            scroll_behavior,
15064            is_selection_reversed,
15065        ));
15066    }
15067
15068    pub fn select_smaller_syntax_node(
15069        &mut self,
15070        _: &SelectSmallerSyntaxNode,
15071        window: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15075
15076        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15077            self.select_syntax_node_history.pop()
15078        {
15079            if let Some(selection) = selections.last_mut() {
15080                selection.reversed = is_selection_reversed;
15081            }
15082
15083            self.select_syntax_node_history.disable_clearing = true;
15084            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15085                s.select(selections.to_vec());
15086            });
15087            self.select_syntax_node_history.disable_clearing = false;
15088
15089            match scroll_behavior {
15090                SelectSyntaxNodeScrollBehavior::CursorTop => {
15091                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15092                }
15093                SelectSyntaxNodeScrollBehavior::FitSelection => {
15094                    self.request_autoscroll(Autoscroll::fit(), cx);
15095                }
15096                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15097                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15098                }
15099            }
15100        }
15101    }
15102
15103    pub fn unwrap_syntax_node(
15104        &mut self,
15105        _: &UnwrapSyntaxNode,
15106        window: &mut Window,
15107        cx: &mut Context<Self>,
15108    ) {
15109        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15110
15111        let buffer = self.buffer.read(cx).snapshot(cx);
15112        let selections = self
15113            .selections
15114            .all::<usize>(cx)
15115            .into_iter()
15116            // subtracting the offset requires sorting
15117            .sorted_by_key(|i| i.start);
15118
15119        let full_edits = selections
15120            .into_iter()
15121            .filter_map(|selection| {
15122                // Only requires two branches once if-let-chains stabilize (#53667)
15123                let child = if !selection.is_empty() {
15124                    selection.range()
15125                } else if let Some((_, ancestor_range)) =
15126                    buffer.syntax_ancestor(selection.start..selection.end)
15127                {
15128                    match ancestor_range {
15129                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15130                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15131                    }
15132                } else {
15133                    selection.range()
15134                };
15135
15136                let mut parent = child.clone();
15137                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15138                    parent = match ancestor_range {
15139                        MultiOrSingleBufferOffsetRange::Single(range) => range,
15140                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
15141                    };
15142                    if parent.start < child.start || parent.end > child.end {
15143                        break;
15144                    }
15145                }
15146
15147                if parent == child {
15148                    return None;
15149                }
15150                let text = buffer.text_for_range(child).collect::<String>();
15151                Some((selection.id, parent, text))
15152            })
15153            .collect::<Vec<_>>();
15154
15155        self.transact(window, cx, |this, window, cx| {
15156            this.buffer.update(cx, |buffer, cx| {
15157                buffer.edit(
15158                    full_edits
15159                        .iter()
15160                        .map(|(_, p, t)| (p.clone(), t.clone()))
15161                        .collect::<Vec<_>>(),
15162                    None,
15163                    cx,
15164                );
15165            });
15166            this.change_selections(Default::default(), window, cx, |s| {
15167                let mut offset = 0;
15168                let mut selections = vec![];
15169                for (id, parent, text) in full_edits {
15170                    let start = parent.start - offset;
15171                    offset += parent.len() - text.len();
15172                    selections.push(Selection {
15173                        id,
15174                        start,
15175                        end: start + text.len(),
15176                        reversed: false,
15177                        goal: Default::default(),
15178                    });
15179                }
15180                s.select(selections);
15181            });
15182        });
15183    }
15184
15185    pub fn select_next_syntax_node(
15186        &mut self,
15187        _: &SelectNextSyntaxNode,
15188        window: &mut Window,
15189        cx: &mut Context<Self>,
15190    ) {
15191        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15192        if old_selections.is_empty() {
15193            return;
15194        }
15195
15196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15197
15198        let buffer = self.buffer.read(cx).snapshot(cx);
15199        let mut selected_sibling = false;
15200
15201        let new_selections = old_selections
15202            .iter()
15203            .map(|selection| {
15204                let old_range = selection.start..selection.end;
15205
15206                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15207                    let new_range = node.byte_range();
15208                    selected_sibling = true;
15209                    Selection {
15210                        id: selection.id,
15211                        start: new_range.start,
15212                        end: new_range.end,
15213                        goal: SelectionGoal::None,
15214                        reversed: selection.reversed,
15215                    }
15216                } else {
15217                    selection.clone()
15218                }
15219            })
15220            .collect::<Vec<_>>();
15221
15222        if selected_sibling {
15223            self.change_selections(
15224                SelectionEffects::scroll(Autoscroll::fit()),
15225                window,
15226                cx,
15227                |s| {
15228                    s.select(new_selections);
15229                },
15230            );
15231        }
15232    }
15233
15234    pub fn select_prev_syntax_node(
15235        &mut self,
15236        _: &SelectPreviousSyntaxNode,
15237        window: &mut Window,
15238        cx: &mut Context<Self>,
15239    ) {
15240        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
15241        if old_selections.is_empty() {
15242            return;
15243        }
15244
15245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15246
15247        let buffer = self.buffer.read(cx).snapshot(cx);
15248        let mut selected_sibling = false;
15249
15250        let new_selections = old_selections
15251            .iter()
15252            .map(|selection| {
15253                let old_range = selection.start..selection.end;
15254
15255                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15256                    let new_range = node.byte_range();
15257                    selected_sibling = true;
15258                    Selection {
15259                        id: selection.id,
15260                        start: new_range.start,
15261                        end: new_range.end,
15262                        goal: SelectionGoal::None,
15263                        reversed: selection.reversed,
15264                    }
15265                } else {
15266                    selection.clone()
15267                }
15268            })
15269            .collect::<Vec<_>>();
15270
15271        if selected_sibling {
15272            self.change_selections(
15273                SelectionEffects::scroll(Autoscroll::fit()),
15274                window,
15275                cx,
15276                |s| {
15277                    s.select(new_selections);
15278                },
15279            );
15280        }
15281    }
15282
15283    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15284        if !EditorSettings::get_global(cx).gutter.runnables {
15285            self.clear_tasks();
15286            return Task::ready(());
15287        }
15288        let project = self.project().map(Entity::downgrade);
15289        let task_sources = self.lsp_task_sources(cx);
15290        let multi_buffer = self.buffer.downgrade();
15291        cx.spawn_in(window, async move |editor, cx| {
15292            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15293            let Some(project) = project.and_then(|p| p.upgrade()) else {
15294                return;
15295            };
15296            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15297                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15298            }) else {
15299                return;
15300            };
15301
15302            let hide_runnables = project
15303                .update(cx, |project, _| project.is_via_collab())
15304                .unwrap_or(true);
15305            if hide_runnables {
15306                return;
15307            }
15308            let new_rows =
15309                cx.background_spawn({
15310                    let snapshot = display_snapshot.clone();
15311                    async move {
15312                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15313                    }
15314                })
15315                    .await;
15316            let Ok(lsp_tasks) =
15317                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15318            else {
15319                return;
15320            };
15321            let lsp_tasks = lsp_tasks.await;
15322
15323            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15324                lsp_tasks
15325                    .into_iter()
15326                    .flat_map(|(kind, tasks)| {
15327                        tasks.into_iter().filter_map(move |(location, task)| {
15328                            Some((kind.clone(), location?, task))
15329                        })
15330                    })
15331                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15332                        let buffer = location.target.buffer;
15333                        let buffer_snapshot = buffer.read(cx).snapshot();
15334                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
15335                            |(excerpt_id, snapshot, _)| {
15336                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15337                                    display_snapshot
15338                                        .buffer_snapshot
15339                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15340                                } else {
15341                                    None
15342                                }
15343                            },
15344                        );
15345                        if let Some(offset) = offset {
15346                            let task_buffer_range =
15347                                location.target.range.to_point(&buffer_snapshot);
15348                            let context_buffer_range =
15349                                task_buffer_range.to_offset(&buffer_snapshot);
15350                            let context_range = BufferOffset(context_buffer_range.start)
15351                                ..BufferOffset(context_buffer_range.end);
15352
15353                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15354                                .or_insert_with(|| RunnableTasks {
15355                                    templates: Vec::new(),
15356                                    offset,
15357                                    column: task_buffer_range.start.column,
15358                                    extra_variables: HashMap::default(),
15359                                    context_range,
15360                                })
15361                                .templates
15362                                .push((kind, task.original_task().clone()));
15363                        }
15364
15365                        acc
15366                    })
15367            }) else {
15368                return;
15369            };
15370
15371            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15372                buffer.language_settings(cx).tasks.prefer_lsp
15373            }) else {
15374                return;
15375            };
15376
15377            let rows = Self::runnable_rows(
15378                project,
15379                display_snapshot,
15380                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15381                new_rows,
15382                cx.clone(),
15383            )
15384            .await;
15385            editor
15386                .update(cx, |editor, _| {
15387                    editor.clear_tasks();
15388                    for (key, mut value) in rows {
15389                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15390                            value.templates.extend(lsp_tasks.templates);
15391                        }
15392
15393                        editor.insert_tasks(key, value);
15394                    }
15395                    for (key, value) in lsp_tasks_by_rows {
15396                        editor.insert_tasks(key, value);
15397                    }
15398                })
15399                .ok();
15400        })
15401    }
15402    fn fetch_runnable_ranges(
15403        snapshot: &DisplaySnapshot,
15404        range: Range<Anchor>,
15405    ) -> Vec<language::RunnableRange> {
15406        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15407    }
15408
15409    fn runnable_rows(
15410        project: Entity<Project>,
15411        snapshot: DisplaySnapshot,
15412        prefer_lsp: bool,
15413        runnable_ranges: Vec<RunnableRange>,
15414        cx: AsyncWindowContext,
15415    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15416        cx.spawn(async move |cx| {
15417            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15418            for mut runnable in runnable_ranges {
15419                let Some(tasks) = cx
15420                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15421                    .ok()
15422                else {
15423                    continue;
15424                };
15425                let mut tasks = tasks.await;
15426
15427                if prefer_lsp {
15428                    tasks.retain(|(task_kind, _)| {
15429                        !matches!(task_kind, TaskSourceKind::Language { .. })
15430                    });
15431                }
15432                if tasks.is_empty() {
15433                    continue;
15434                }
15435
15436                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15437                let Some(row) = snapshot
15438                    .buffer_snapshot
15439                    .buffer_line_for_row(MultiBufferRow(point.row))
15440                    .map(|(_, range)| range.start.row)
15441                else {
15442                    continue;
15443                };
15444
15445                let context_range =
15446                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15447                runnable_rows.push((
15448                    (runnable.buffer_id, row),
15449                    RunnableTasks {
15450                        templates: tasks,
15451                        offset: snapshot
15452                            .buffer_snapshot
15453                            .anchor_before(runnable.run_range.start),
15454                        context_range,
15455                        column: point.column,
15456                        extra_variables: runnable.extra_captures,
15457                    },
15458                ));
15459            }
15460            runnable_rows
15461        })
15462    }
15463
15464    fn templates_with_tags(
15465        project: &Entity<Project>,
15466        runnable: &mut Runnable,
15467        cx: &mut App,
15468    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15469        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15470            let (worktree_id, file) = project
15471                .buffer_for_id(runnable.buffer, cx)
15472                .and_then(|buffer| buffer.read(cx).file())
15473                .map(|file| (file.worktree_id(cx), file.clone()))
15474                .unzip();
15475
15476            (
15477                project.task_store().read(cx).task_inventory().cloned(),
15478                worktree_id,
15479                file,
15480            )
15481        });
15482
15483        let tags = mem::take(&mut runnable.tags);
15484        let language = runnable.language.clone();
15485        cx.spawn(async move |cx| {
15486            let mut templates_with_tags = Vec::new();
15487            if let Some(inventory) = inventory {
15488                for RunnableTag(tag) in tags {
15489                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15490                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15491                    }) else {
15492                        return templates_with_tags;
15493                    };
15494                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15495                        move |(_, template)| {
15496                            template.tags.iter().any(|source_tag| source_tag == &tag)
15497                        },
15498                    ));
15499                }
15500            }
15501            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15502
15503            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15504                // Strongest source wins; if we have worktree tag binding, prefer that to
15505                // global and language bindings;
15506                // if we have a global binding, prefer that to language binding.
15507                let first_mismatch = templates_with_tags
15508                    .iter()
15509                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15510                if let Some(index) = first_mismatch {
15511                    templates_with_tags.truncate(index);
15512                }
15513            }
15514
15515            templates_with_tags
15516        })
15517    }
15518
15519    pub fn move_to_enclosing_bracket(
15520        &mut self,
15521        _: &MoveToEnclosingBracket,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) {
15525        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15526        self.change_selections(Default::default(), window, cx, |s| {
15527            s.move_offsets_with(|snapshot, selection| {
15528                let Some(enclosing_bracket_ranges) =
15529                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15530                else {
15531                    return;
15532                };
15533
15534                let mut best_length = usize::MAX;
15535                let mut best_inside = false;
15536                let mut best_in_bracket_range = false;
15537                let mut best_destination = None;
15538                for (open, close) in enclosing_bracket_ranges {
15539                    let close = close.to_inclusive();
15540                    let length = close.end() - open.start;
15541                    let inside = selection.start >= open.end && selection.end <= *close.start();
15542                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15543                        || close.contains(&selection.head());
15544
15545                    // If best is next to a bracket and current isn't, skip
15546                    if !in_bracket_range && best_in_bracket_range {
15547                        continue;
15548                    }
15549
15550                    // Prefer smaller lengths unless best is inside and current isn't
15551                    if length > best_length && (best_inside || !inside) {
15552                        continue;
15553                    }
15554
15555                    best_length = length;
15556                    best_inside = inside;
15557                    best_in_bracket_range = in_bracket_range;
15558                    best_destination = Some(
15559                        if close.contains(&selection.start) && close.contains(&selection.end) {
15560                            if inside { open.end } else { open.start }
15561                        } else if inside {
15562                            *close.start()
15563                        } else {
15564                            *close.end()
15565                        },
15566                    );
15567                }
15568
15569                if let Some(destination) = best_destination {
15570                    selection.collapse_to(destination, SelectionGoal::None);
15571                }
15572            })
15573        });
15574    }
15575
15576    pub fn undo_selection(
15577        &mut self,
15578        _: &UndoSelection,
15579        window: &mut Window,
15580        cx: &mut Context<Self>,
15581    ) {
15582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15583        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15584            self.selection_history.mode = SelectionHistoryMode::Undoing;
15585            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15586                this.end_selection(window, cx);
15587                this.change_selections(
15588                    SelectionEffects::scroll(Autoscroll::newest()),
15589                    window,
15590                    cx,
15591                    |s| s.select_anchors(entry.selections.to_vec()),
15592                );
15593            });
15594            self.selection_history.mode = SelectionHistoryMode::Normal;
15595
15596            self.select_next_state = entry.select_next_state;
15597            self.select_prev_state = entry.select_prev_state;
15598            self.add_selections_state = entry.add_selections_state;
15599        }
15600    }
15601
15602    pub fn redo_selection(
15603        &mut self,
15604        _: &RedoSelection,
15605        window: &mut Window,
15606        cx: &mut Context<Self>,
15607    ) {
15608        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15609        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15610            self.selection_history.mode = SelectionHistoryMode::Redoing;
15611            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15612                this.end_selection(window, cx);
15613                this.change_selections(
15614                    SelectionEffects::scroll(Autoscroll::newest()),
15615                    window,
15616                    cx,
15617                    |s| s.select_anchors(entry.selections.to_vec()),
15618                );
15619            });
15620            self.selection_history.mode = SelectionHistoryMode::Normal;
15621
15622            self.select_next_state = entry.select_next_state;
15623            self.select_prev_state = entry.select_prev_state;
15624            self.add_selections_state = entry.add_selections_state;
15625        }
15626    }
15627
15628    pub fn expand_excerpts(
15629        &mut self,
15630        action: &ExpandExcerpts,
15631        _: &mut Window,
15632        cx: &mut Context<Self>,
15633    ) {
15634        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15635    }
15636
15637    pub fn expand_excerpts_down(
15638        &mut self,
15639        action: &ExpandExcerptsDown,
15640        _: &mut Window,
15641        cx: &mut Context<Self>,
15642    ) {
15643        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15644    }
15645
15646    pub fn expand_excerpts_up(
15647        &mut self,
15648        action: &ExpandExcerptsUp,
15649        _: &mut Window,
15650        cx: &mut Context<Self>,
15651    ) {
15652        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15653    }
15654
15655    pub fn expand_excerpts_for_direction(
15656        &mut self,
15657        lines: u32,
15658        direction: ExpandExcerptDirection,
15659
15660        cx: &mut Context<Self>,
15661    ) {
15662        let selections = self.selections.disjoint_anchors();
15663
15664        let lines = if lines == 0 {
15665            EditorSettings::get_global(cx).expand_excerpt_lines
15666        } else {
15667            lines
15668        };
15669
15670        self.buffer.update(cx, |buffer, cx| {
15671            let snapshot = buffer.snapshot(cx);
15672            let mut excerpt_ids = selections
15673                .iter()
15674                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15675                .collect::<Vec<_>>();
15676            excerpt_ids.sort();
15677            excerpt_ids.dedup();
15678            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15679        })
15680    }
15681
15682    pub fn expand_excerpt(
15683        &mut self,
15684        excerpt: ExcerptId,
15685        direction: ExpandExcerptDirection,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) {
15689        let current_scroll_position = self.scroll_position(cx);
15690        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15691        let mut should_scroll_up = false;
15692
15693        if direction == ExpandExcerptDirection::Down {
15694            let multi_buffer = self.buffer.read(cx);
15695            let snapshot = multi_buffer.snapshot(cx);
15696            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15697                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15698                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15699            {
15700                let buffer_snapshot = buffer.read(cx).snapshot();
15701                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15702                let last_row = buffer_snapshot.max_point().row;
15703                let lines_below = last_row.saturating_sub(excerpt_end_row);
15704                should_scroll_up = lines_below >= lines_to_expand;
15705            }
15706        }
15707
15708        self.buffer.update(cx, |buffer, cx| {
15709            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15710        });
15711
15712        if should_scroll_up {
15713            let new_scroll_position =
15714                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15715            self.set_scroll_position(new_scroll_position, window, cx);
15716        }
15717    }
15718
15719    pub fn go_to_singleton_buffer_point(
15720        &mut self,
15721        point: Point,
15722        window: &mut Window,
15723        cx: &mut Context<Self>,
15724    ) {
15725        self.go_to_singleton_buffer_range(point..point, window, cx);
15726    }
15727
15728    pub fn go_to_singleton_buffer_range(
15729        &mut self,
15730        range: Range<Point>,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) {
15734        let multibuffer = self.buffer().read(cx);
15735        let Some(buffer) = multibuffer.as_singleton() else {
15736            return;
15737        };
15738        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15739            return;
15740        };
15741        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15742            return;
15743        };
15744        self.change_selections(
15745            SelectionEffects::default().nav_history(true),
15746            window,
15747            cx,
15748            |s| s.select_anchor_ranges([start..end]),
15749        );
15750    }
15751
15752    pub fn go_to_diagnostic(
15753        &mut self,
15754        action: &GoToDiagnostic,
15755        window: &mut Window,
15756        cx: &mut Context<Self>,
15757    ) {
15758        if !self.diagnostics_enabled() {
15759            return;
15760        }
15761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15762        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15763    }
15764
15765    pub fn go_to_prev_diagnostic(
15766        &mut self,
15767        action: &GoToPreviousDiagnostic,
15768        window: &mut Window,
15769        cx: &mut Context<Self>,
15770    ) {
15771        if !self.diagnostics_enabled() {
15772            return;
15773        }
15774        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15775        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15776    }
15777
15778    pub fn go_to_diagnostic_impl(
15779        &mut self,
15780        direction: Direction,
15781        severity: GoToDiagnosticSeverityFilter,
15782        window: &mut Window,
15783        cx: &mut Context<Self>,
15784    ) {
15785        let buffer = self.buffer.read(cx).snapshot(cx);
15786        let selection = self.selections.newest::<usize>(cx);
15787
15788        let mut active_group_id = None;
15789        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15790            && active_group.active_range.start.to_offset(&buffer) == selection.start
15791        {
15792            active_group_id = Some(active_group.group_id);
15793        }
15794
15795        fn filtered(
15796            snapshot: EditorSnapshot,
15797            severity: GoToDiagnosticSeverityFilter,
15798            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15799        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15800            diagnostics
15801                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15802                .filter(|entry| entry.range.start != entry.range.end)
15803                .filter(|entry| !entry.diagnostic.is_unnecessary)
15804                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15805        }
15806
15807        let snapshot = self.snapshot(window, cx);
15808        let before = filtered(
15809            snapshot.clone(),
15810            severity,
15811            buffer
15812                .diagnostics_in_range(0..selection.start)
15813                .filter(|entry| entry.range.start <= selection.start),
15814        );
15815        let after = filtered(
15816            snapshot,
15817            severity,
15818            buffer
15819                .diagnostics_in_range(selection.start..buffer.len())
15820                .filter(|entry| entry.range.start >= selection.start),
15821        );
15822
15823        let mut found: Option<DiagnosticEntry<usize>> = None;
15824        if direction == Direction::Prev {
15825            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15826            {
15827                for diagnostic in prev_diagnostics.into_iter().rev() {
15828                    if diagnostic.range.start != selection.start
15829                        || active_group_id
15830                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15831                    {
15832                        found = Some(diagnostic);
15833                        break 'outer;
15834                    }
15835                }
15836            }
15837        } else {
15838            for diagnostic in after.chain(before) {
15839                if diagnostic.range.start != selection.start
15840                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15841                {
15842                    found = Some(diagnostic);
15843                    break;
15844                }
15845            }
15846        }
15847        let Some(next_diagnostic) = found else {
15848            return;
15849        };
15850
15851        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
15852        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
15853            return;
15854        };
15855        self.change_selections(Default::default(), window, cx, |s| {
15856            s.select_ranges(vec![
15857                next_diagnostic.range.start..next_diagnostic.range.start,
15858            ])
15859        });
15860        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15861        self.refresh_edit_prediction(false, true, window, cx);
15862    }
15863
15864    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15866        let snapshot = self.snapshot(window, cx);
15867        let selection = self.selections.newest::<Point>(cx);
15868        self.go_to_hunk_before_or_after_position(
15869            &snapshot,
15870            selection.head(),
15871            Direction::Next,
15872            window,
15873            cx,
15874        );
15875    }
15876
15877    pub fn go_to_hunk_before_or_after_position(
15878        &mut self,
15879        snapshot: &EditorSnapshot,
15880        position: Point,
15881        direction: Direction,
15882        window: &mut Window,
15883        cx: &mut Context<Editor>,
15884    ) {
15885        let row = if direction == Direction::Next {
15886            self.hunk_after_position(snapshot, position)
15887                .map(|hunk| hunk.row_range.start)
15888        } else {
15889            self.hunk_before_position(snapshot, position)
15890        };
15891
15892        if let Some(row) = row {
15893            let destination = Point::new(row.0, 0);
15894            let autoscroll = Autoscroll::center();
15895
15896            self.unfold_ranges(&[destination..destination], false, false, cx);
15897            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15898                s.select_ranges([destination..destination]);
15899            });
15900        }
15901    }
15902
15903    fn hunk_after_position(
15904        &mut self,
15905        snapshot: &EditorSnapshot,
15906        position: Point,
15907    ) -> Option<MultiBufferDiffHunk> {
15908        snapshot
15909            .buffer_snapshot
15910            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15911            .find(|hunk| hunk.row_range.start.0 > position.row)
15912            .or_else(|| {
15913                snapshot
15914                    .buffer_snapshot
15915                    .diff_hunks_in_range(Point::zero()..position)
15916                    .find(|hunk| hunk.row_range.end.0 < position.row)
15917            })
15918    }
15919
15920    fn go_to_prev_hunk(
15921        &mut self,
15922        _: &GoToPreviousHunk,
15923        window: &mut Window,
15924        cx: &mut Context<Self>,
15925    ) {
15926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15927        let snapshot = self.snapshot(window, cx);
15928        let selection = self.selections.newest::<Point>(cx);
15929        self.go_to_hunk_before_or_after_position(
15930            &snapshot,
15931            selection.head(),
15932            Direction::Prev,
15933            window,
15934            cx,
15935        );
15936    }
15937
15938    fn hunk_before_position(
15939        &mut self,
15940        snapshot: &EditorSnapshot,
15941        position: Point,
15942    ) -> Option<MultiBufferRow> {
15943        snapshot
15944            .buffer_snapshot
15945            .diff_hunk_before(position)
15946            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15947    }
15948
15949    fn go_to_next_change(
15950        &mut self,
15951        _: &GoToNextChange,
15952        window: &mut Window,
15953        cx: &mut Context<Self>,
15954    ) {
15955        if let Some(selections) = self
15956            .change_list
15957            .next_change(1, Direction::Next)
15958            .map(|s| s.to_vec())
15959        {
15960            self.change_selections(Default::default(), window, cx, |s| {
15961                let map = s.display_map();
15962                s.select_display_ranges(selections.iter().map(|a| {
15963                    let point = a.to_display_point(&map);
15964                    point..point
15965                }))
15966            })
15967        }
15968    }
15969
15970    fn go_to_previous_change(
15971        &mut self,
15972        _: &GoToPreviousChange,
15973        window: &mut Window,
15974        cx: &mut Context<Self>,
15975    ) {
15976        if let Some(selections) = self
15977            .change_list
15978            .next_change(1, Direction::Prev)
15979            .map(|s| s.to_vec())
15980        {
15981            self.change_selections(Default::default(), window, cx, |s| {
15982                let map = s.display_map();
15983                s.select_display_ranges(selections.iter().map(|a| {
15984                    let point = a.to_display_point(&map);
15985                    point..point
15986                }))
15987            })
15988        }
15989    }
15990
15991    pub fn go_to_next_document_highlight(
15992        &mut self,
15993        _: &GoToNextDocumentHighlight,
15994        window: &mut Window,
15995        cx: &mut Context<Self>,
15996    ) {
15997        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
15998    }
15999
16000    pub fn go_to_prev_document_highlight(
16001        &mut self,
16002        _: &GoToPreviousDocumentHighlight,
16003        window: &mut Window,
16004        cx: &mut Context<Self>,
16005    ) {
16006        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16007    }
16008
16009    pub fn go_to_document_highlight_before_or_after_position(
16010        &mut self,
16011        direction: Direction,
16012        window: &mut Window,
16013        cx: &mut Context<Editor>,
16014    ) {
16015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16016        let snapshot = self.snapshot(window, cx);
16017        let buffer = &snapshot.buffer_snapshot;
16018        let position = self.selections.newest::<Point>(cx).head();
16019        let anchor_position = buffer.anchor_after(position);
16020
16021        // Get all document highlights (both read and write)
16022        let mut all_highlights = Vec::new();
16023
16024        if let Some((_, read_highlights)) = self
16025            .background_highlights
16026            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16027        {
16028            all_highlights.extend(read_highlights.iter());
16029        }
16030
16031        if let Some((_, write_highlights)) = self
16032            .background_highlights
16033            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16034        {
16035            all_highlights.extend(write_highlights.iter());
16036        }
16037
16038        if all_highlights.is_empty() {
16039            return;
16040        }
16041
16042        // Sort highlights by position
16043        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16044
16045        let target_highlight = match direction {
16046            Direction::Next => {
16047                // Find the first highlight after the current position
16048                all_highlights
16049                    .iter()
16050                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16051            }
16052            Direction::Prev => {
16053                // Find the last highlight before the current position
16054                all_highlights
16055                    .iter()
16056                    .rev()
16057                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16058            }
16059        };
16060
16061        if let Some(highlight) = target_highlight {
16062            let destination = highlight.start.to_point(buffer);
16063            let autoscroll = Autoscroll::center();
16064
16065            self.unfold_ranges(&[destination..destination], false, false, cx);
16066            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16067                s.select_ranges([destination..destination]);
16068            });
16069        }
16070    }
16071
16072    fn go_to_line<T: 'static>(
16073        &mut self,
16074        position: Anchor,
16075        highlight_color: Option<Hsla>,
16076        window: &mut Window,
16077        cx: &mut Context<Self>,
16078    ) {
16079        let snapshot = self.snapshot(window, cx).display_snapshot;
16080        let position = position.to_point(&snapshot.buffer_snapshot);
16081        let start = snapshot
16082            .buffer_snapshot
16083            .clip_point(Point::new(position.row, 0), Bias::Left);
16084        let end = start + Point::new(1, 0);
16085        let start = snapshot.buffer_snapshot.anchor_before(start);
16086        let end = snapshot.buffer_snapshot.anchor_before(end);
16087
16088        self.highlight_rows::<T>(
16089            start..end,
16090            highlight_color
16091                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16092            Default::default(),
16093            cx,
16094        );
16095
16096        if self.buffer.read(cx).is_singleton() {
16097            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16098        }
16099    }
16100
16101    pub fn go_to_definition(
16102        &mut self,
16103        _: &GoToDefinition,
16104        window: &mut Window,
16105        cx: &mut Context<Self>,
16106    ) -> Task<Result<Navigated>> {
16107        let definition =
16108            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16109        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16110        cx.spawn_in(window, async move |editor, cx| {
16111            if definition.await? == Navigated::Yes {
16112                return Ok(Navigated::Yes);
16113            }
16114            match fallback_strategy {
16115                GoToDefinitionFallback::None => Ok(Navigated::No),
16116                GoToDefinitionFallback::FindAllReferences => {
16117                    match editor.update_in(cx, |editor, window, cx| {
16118                        editor.find_all_references(&FindAllReferences, window, cx)
16119                    })? {
16120                        Some(references) => references.await,
16121                        None => Ok(Navigated::No),
16122                    }
16123                }
16124            }
16125        })
16126    }
16127
16128    pub fn go_to_declaration(
16129        &mut self,
16130        _: &GoToDeclaration,
16131        window: &mut Window,
16132        cx: &mut Context<Self>,
16133    ) -> Task<Result<Navigated>> {
16134        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16135    }
16136
16137    pub fn go_to_declaration_split(
16138        &mut self,
16139        _: &GoToDeclaration,
16140        window: &mut Window,
16141        cx: &mut Context<Self>,
16142    ) -> Task<Result<Navigated>> {
16143        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16144    }
16145
16146    pub fn go_to_implementation(
16147        &mut self,
16148        _: &GoToImplementation,
16149        window: &mut Window,
16150        cx: &mut Context<Self>,
16151    ) -> Task<Result<Navigated>> {
16152        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16153    }
16154
16155    pub fn go_to_implementation_split(
16156        &mut self,
16157        _: &GoToImplementationSplit,
16158        window: &mut Window,
16159        cx: &mut Context<Self>,
16160    ) -> Task<Result<Navigated>> {
16161        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16162    }
16163
16164    pub fn go_to_type_definition(
16165        &mut self,
16166        _: &GoToTypeDefinition,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) -> Task<Result<Navigated>> {
16170        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16171    }
16172
16173    pub fn go_to_definition_split(
16174        &mut self,
16175        _: &GoToDefinitionSplit,
16176        window: &mut Window,
16177        cx: &mut Context<Self>,
16178    ) -> Task<Result<Navigated>> {
16179        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16180    }
16181
16182    pub fn go_to_type_definition_split(
16183        &mut self,
16184        _: &GoToTypeDefinitionSplit,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) -> Task<Result<Navigated>> {
16188        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16189    }
16190
16191    fn go_to_definition_of_kind(
16192        &mut self,
16193        kind: GotoDefinitionKind,
16194        split: bool,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) -> Task<Result<Navigated>> {
16198        let Some(provider) = self.semantics_provider.clone() else {
16199            return Task::ready(Ok(Navigated::No));
16200        };
16201        let head = self.selections.newest::<usize>(cx).head();
16202        let buffer = self.buffer.read(cx);
16203        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16204            return Task::ready(Ok(Navigated::No));
16205        };
16206        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16207            return Task::ready(Ok(Navigated::No));
16208        };
16209
16210        cx.spawn_in(window, async move |editor, cx| {
16211            let Some(definitions) = definitions.await? else {
16212                return Ok(Navigated::No);
16213            };
16214            let navigated = editor
16215                .update_in(cx, |editor, window, cx| {
16216                    editor.navigate_to_hover_links(
16217                        Some(kind),
16218                        definitions
16219                            .into_iter()
16220                            .filter(|location| {
16221                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16222                            })
16223                            .map(HoverLink::Text)
16224                            .collect::<Vec<_>>(),
16225                        split,
16226                        window,
16227                        cx,
16228                    )
16229                })?
16230                .await?;
16231            anyhow::Ok(navigated)
16232        })
16233    }
16234
16235    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16236        let selection = self.selections.newest_anchor();
16237        let head = selection.head();
16238        let tail = selection.tail();
16239
16240        let Some((buffer, start_position)) =
16241            self.buffer.read(cx).text_anchor_for_position(head, cx)
16242        else {
16243            return;
16244        };
16245
16246        let end_position = if head != tail {
16247            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16248                return;
16249            };
16250            Some(pos)
16251        } else {
16252            None
16253        };
16254
16255        let url_finder = cx.spawn_in(window, async move |editor, cx| {
16256            let url = if let Some(end_pos) = end_position {
16257                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16258            } else {
16259                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16260            };
16261
16262            if let Some(url) = url {
16263                editor.update(cx, |_, cx| {
16264                    cx.open_url(&url);
16265                })
16266            } else {
16267                Ok(())
16268            }
16269        });
16270
16271        url_finder.detach();
16272    }
16273
16274    pub fn open_selected_filename(
16275        &mut self,
16276        _: &OpenSelectedFilename,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        let Some(workspace) = self.workspace() else {
16281            return;
16282        };
16283
16284        let position = self.selections.newest_anchor().head();
16285
16286        let Some((buffer, buffer_position)) =
16287            self.buffer.read(cx).text_anchor_for_position(position, cx)
16288        else {
16289            return;
16290        };
16291
16292        let project = self.project.clone();
16293
16294        cx.spawn_in(window, async move |_, cx| {
16295            let result = find_file(&buffer, project, buffer_position, cx).await;
16296
16297            if let Some((_, path)) = result {
16298                workspace
16299                    .update_in(cx, |workspace, window, cx| {
16300                        workspace.open_resolved_path(path, window, cx)
16301                    })?
16302                    .await?;
16303            }
16304            anyhow::Ok(())
16305        })
16306        .detach();
16307    }
16308
16309    pub(crate) fn navigate_to_hover_links(
16310        &mut self,
16311        kind: Option<GotoDefinitionKind>,
16312        definitions: Vec<HoverLink>,
16313        split: bool,
16314        window: &mut Window,
16315        cx: &mut Context<Editor>,
16316    ) -> Task<Result<Navigated>> {
16317        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16318        let mut first_url_or_file = None;
16319        let definitions: Vec<_> = definitions
16320            .into_iter()
16321            .filter_map(|def| match def {
16322                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16323                HoverLink::InlayHint(lsp_location, server_id) => {
16324                    let computation =
16325                        self.compute_target_location(lsp_location, server_id, window, cx);
16326                    Some(cx.background_spawn(computation))
16327                }
16328                HoverLink::Url(url) => {
16329                    first_url_or_file = Some(Either::Left(url));
16330                    None
16331                }
16332                HoverLink::File(path) => {
16333                    first_url_or_file = Some(Either::Right(path));
16334                    None
16335                }
16336            })
16337            .collect();
16338
16339        let workspace = self.workspace();
16340
16341        cx.spawn_in(window, async move |editor, acx| {
16342            let mut locations: Vec<Location> = future::join_all(definitions)
16343                .await
16344                .into_iter()
16345                .filter_map(|location| location.transpose())
16346                .collect::<Result<_>>()
16347                .context("location tasks")?;
16348
16349            if locations.len() > 1 {
16350                let Some(workspace) = workspace else {
16351                    return Ok(Navigated::No);
16352                };
16353
16354                let tab_kind = match kind {
16355                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16356                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16357                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16358                    Some(GotoDefinitionKind::Type) => "Types",
16359                };
16360                let title = editor
16361                    .update_in(acx, |_, _, cx| {
16362                        let target = locations
16363                            .iter()
16364                            .map(|location| {
16365                                location
16366                                    .buffer
16367                                    .read(cx)
16368                                    .text_for_range(location.range.clone())
16369                                    .collect::<String>()
16370                            })
16371                            .filter(|text| !text.contains('\n'))
16372                            .unique()
16373                            .take(3)
16374                            .join(", ");
16375                        if target.is_empty() {
16376                            tab_kind.to_owned()
16377                        } else {
16378                            format!("{tab_kind} for {target}")
16379                        }
16380                    })
16381                    .context("buffer title")?;
16382
16383                let opened = workspace
16384                    .update_in(acx, |workspace, window, cx| {
16385                        Self::open_locations_in_multibuffer(
16386                            workspace,
16387                            locations,
16388                            title,
16389                            split,
16390                            MultibufferSelectionMode::First,
16391                            window,
16392                            cx,
16393                        )
16394                    })
16395                    .is_ok();
16396
16397                anyhow::Ok(Navigated::from_bool(opened))
16398            } else if locations.is_empty() {
16399                // If there is one url or file, open it directly
16400                match first_url_or_file {
16401                    Some(Either::Left(url)) => {
16402                        acx.update(|_, cx| cx.open_url(&url))?;
16403                        Ok(Navigated::Yes)
16404                    }
16405                    Some(Either::Right(path)) => {
16406                        let Some(workspace) = workspace else {
16407                            return Ok(Navigated::No);
16408                        };
16409
16410                        workspace
16411                            .update_in(acx, |workspace, window, cx| {
16412                                workspace.open_resolved_path(path, window, cx)
16413                            })?
16414                            .await?;
16415                        Ok(Navigated::Yes)
16416                    }
16417                    None => Ok(Navigated::No),
16418                }
16419            } else {
16420                let Some(workspace) = workspace else {
16421                    return Ok(Navigated::No);
16422                };
16423
16424                let target = locations.pop().unwrap();
16425                editor.update_in(acx, |editor, window, cx| {
16426                    let range = target.range.to_point(target.buffer.read(cx));
16427                    let range = editor.range_for_match(&range);
16428                    let range = collapse_multiline_range(range);
16429
16430                    if !split
16431                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16432                    {
16433                        editor.go_to_singleton_buffer_range(range, window, cx);
16434                    } else {
16435                        let pane = workspace.read(cx).active_pane().clone();
16436                        window.defer(cx, move |window, cx| {
16437                            let target_editor: Entity<Self> =
16438                                workspace.update(cx, |workspace, cx| {
16439                                    let pane = if split {
16440                                        workspace.adjacent_pane(window, cx)
16441                                    } else {
16442                                        workspace.active_pane().clone()
16443                                    };
16444
16445                                    workspace.open_project_item(
16446                                        pane,
16447                                        target.buffer.clone(),
16448                                        true,
16449                                        true,
16450                                        window,
16451                                        cx,
16452                                    )
16453                                });
16454                            target_editor.update(cx, |target_editor, cx| {
16455                                // When selecting a definition in a different buffer, disable the nav history
16456                                // to avoid creating a history entry at the previous cursor location.
16457                                pane.update(cx, |pane, _| pane.disable_history());
16458                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16459                                pane.update(cx, |pane, _| pane.enable_history());
16460                            });
16461                        });
16462                    }
16463                    Navigated::Yes
16464                })
16465            }
16466        })
16467    }
16468
16469    fn compute_target_location(
16470        &self,
16471        lsp_location: lsp::Location,
16472        server_id: LanguageServerId,
16473        window: &mut Window,
16474        cx: &mut Context<Self>,
16475    ) -> Task<anyhow::Result<Option<Location>>> {
16476        let Some(project) = self.project.clone() else {
16477            return Task::ready(Ok(None));
16478        };
16479
16480        cx.spawn_in(window, async move |editor, cx| {
16481            let location_task = editor.update(cx, |_, cx| {
16482                project.update(cx, |project, cx| {
16483                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16484                })
16485            })?;
16486            let location = Some({
16487                let target_buffer_handle = location_task.await.context("open local buffer")?;
16488                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16489                    let target_start = target_buffer
16490                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16491                    let target_end = target_buffer
16492                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16493                    target_buffer.anchor_after(target_start)
16494                        ..target_buffer.anchor_before(target_end)
16495                })?;
16496                Location {
16497                    buffer: target_buffer_handle,
16498                    range,
16499                }
16500            });
16501            Ok(location)
16502        })
16503    }
16504
16505    pub fn find_all_references(
16506        &mut self,
16507        _: &FindAllReferences,
16508        window: &mut Window,
16509        cx: &mut Context<Self>,
16510    ) -> Option<Task<Result<Navigated>>> {
16511        let selection = self.selections.newest::<usize>(cx);
16512        let multi_buffer = self.buffer.read(cx);
16513        let head = selection.head();
16514
16515        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16516        let head_anchor = multi_buffer_snapshot.anchor_at(
16517            head,
16518            if head < selection.tail() {
16519                Bias::Right
16520            } else {
16521                Bias::Left
16522            },
16523        );
16524
16525        match self
16526            .find_all_references_task_sources
16527            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16528        {
16529            Ok(_) => {
16530                log::info!(
16531                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16532                );
16533                return None;
16534            }
16535            Err(i) => {
16536                self.find_all_references_task_sources.insert(i, head_anchor);
16537            }
16538        }
16539
16540        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16541        let workspace = self.workspace()?;
16542        let project = workspace.read(cx).project().clone();
16543        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16544        Some(cx.spawn_in(window, async move |editor, cx| {
16545            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16546                if let Ok(i) = editor
16547                    .find_all_references_task_sources
16548                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16549                {
16550                    editor.find_all_references_task_sources.remove(i);
16551                }
16552            });
16553
16554            let Some(locations) = references.await? else {
16555                return anyhow::Ok(Navigated::No);
16556            };
16557            if locations.is_empty() {
16558                return anyhow::Ok(Navigated::No);
16559            }
16560
16561            workspace.update_in(cx, |workspace, window, cx| {
16562                let target = locations
16563                    .iter()
16564                    .map(|location| {
16565                        location
16566                            .buffer
16567                            .read(cx)
16568                            .text_for_range(location.range.clone())
16569                            .collect::<String>()
16570                    })
16571                    .filter(|text| !text.contains('\n'))
16572                    .unique()
16573                    .take(3)
16574                    .join(", ");
16575                let title = if target.is_empty() {
16576                    "References".to_owned()
16577                } else {
16578                    format!("References to {target}")
16579                };
16580                Self::open_locations_in_multibuffer(
16581                    workspace,
16582                    locations,
16583                    title,
16584                    false,
16585                    MultibufferSelectionMode::First,
16586                    window,
16587                    cx,
16588                );
16589                Navigated::Yes
16590            })
16591        }))
16592    }
16593
16594    /// Opens a multibuffer with the given project locations in it
16595    pub fn open_locations_in_multibuffer(
16596        workspace: &mut Workspace,
16597        mut locations: Vec<Location>,
16598        title: String,
16599        split: bool,
16600        multibuffer_selection_mode: MultibufferSelectionMode,
16601        window: &mut Window,
16602        cx: &mut Context<Workspace>,
16603    ) {
16604        if locations.is_empty() {
16605            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16606            return;
16607        }
16608
16609        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16610
16611        let mut locations = locations.into_iter().peekable();
16612        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16613        let capability = workspace.project().read(cx).capability();
16614
16615        // a key to find existing multibuffer editors with the same set of locations
16616        // to prevent us from opening more and more multibuffer tabs for searches and the like
16617        let mut key = (title.clone(), vec![]);
16618        let excerpt_buffer = cx.new(|cx| {
16619            let key = &mut key.1;
16620            let mut multibuffer = MultiBuffer::new(capability);
16621            while let Some(location) = locations.next() {
16622                let buffer = location.buffer.read(cx);
16623                let mut ranges_for_buffer = Vec::new();
16624                let range = location.range.to_point(buffer);
16625                ranges_for_buffer.push(range.clone());
16626
16627                while let Some(next_location) =
16628                    locations.next_if(|next_location| next_location.buffer == location.buffer)
16629                {
16630                    ranges_for_buffer.push(next_location.range.to_point(buffer));
16631                }
16632
16633                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16634                key.push((
16635                    location.buffer.read(cx).remote_id(),
16636                    ranges_for_buffer.clone(),
16637                ));
16638                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16639                    PathKey::for_buffer(&location.buffer, cx),
16640                    location.buffer.clone(),
16641                    ranges_for_buffer,
16642                    multibuffer_context_lines(cx),
16643                    cx,
16644                );
16645                ranges.extend(new_ranges)
16646            }
16647
16648            multibuffer.with_title(title)
16649        });
16650        let existing = workspace.active_pane().update(cx, |pane, cx| {
16651            pane.items()
16652                .filter_map(|item| item.downcast::<Editor>())
16653                .find(|editor| {
16654                    editor
16655                        .read(cx)
16656                        .lookup_key
16657                        .as_ref()
16658                        .and_then(|it| {
16659                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
16660                        })
16661                        .is_some_and(|it| *it == key)
16662                })
16663        });
16664        let editor = existing.unwrap_or_else(|| {
16665            cx.new(|cx| {
16666                let mut editor = Editor::for_multibuffer(
16667                    excerpt_buffer,
16668                    Some(workspace.project().clone()),
16669                    window,
16670                    cx,
16671                );
16672                editor.lookup_key = Some(Box::new(key));
16673                editor
16674            })
16675        });
16676        editor.update(cx, |editor, cx| {
16677            match multibuffer_selection_mode {
16678                MultibufferSelectionMode::First => {
16679                    if let Some(first_range) = ranges.first() {
16680                        editor.change_selections(
16681                            SelectionEffects::no_scroll(),
16682                            window,
16683                            cx,
16684                            |selections| {
16685                                selections.clear_disjoint();
16686                                selections
16687                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16688                            },
16689                        );
16690                    }
16691                    editor.highlight_background::<Self>(
16692                        &ranges,
16693                        |theme| theme.colors().editor_highlighted_line_background,
16694                        cx,
16695                    );
16696                }
16697                MultibufferSelectionMode::All => {
16698                    editor.change_selections(
16699                        SelectionEffects::no_scroll(),
16700                        window,
16701                        cx,
16702                        |selections| {
16703                            selections.clear_disjoint();
16704                            selections.select_anchor_ranges(ranges);
16705                        },
16706                    );
16707                }
16708            }
16709            editor.register_buffers_with_language_servers(cx);
16710        });
16711
16712        let item = Box::new(editor);
16713        let item_id = item.item_id();
16714
16715        if split {
16716            workspace.split_item(SplitDirection::Right, item, window, cx);
16717        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16718            let (preview_item_id, preview_item_idx) =
16719                workspace.active_pane().read_with(cx, |pane, _| {
16720                    (pane.preview_item_id(), pane.preview_item_idx())
16721                });
16722
16723            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
16724
16725            if let Some(preview_item_id) = preview_item_id {
16726                workspace.active_pane().update(cx, |pane, cx| {
16727                    pane.remove_item(preview_item_id, false, false, window, cx);
16728                });
16729            }
16730        } else {
16731            workspace.add_item_to_active_pane(item, None, true, window, cx);
16732        }
16733        workspace.active_pane().update(cx, |pane, cx| {
16734            pane.set_preview_item_id(Some(item_id), cx);
16735        });
16736    }
16737
16738    pub fn rename(
16739        &mut self,
16740        _: &Rename,
16741        window: &mut Window,
16742        cx: &mut Context<Self>,
16743    ) -> Option<Task<Result<()>>> {
16744        use language::ToOffset as _;
16745
16746        let provider = self.semantics_provider.clone()?;
16747        let selection = self.selections.newest_anchor().clone();
16748        let (cursor_buffer, cursor_buffer_position) = self
16749            .buffer
16750            .read(cx)
16751            .text_anchor_for_position(selection.head(), cx)?;
16752        let (tail_buffer, cursor_buffer_position_end) = self
16753            .buffer
16754            .read(cx)
16755            .text_anchor_for_position(selection.tail(), cx)?;
16756        if tail_buffer != cursor_buffer {
16757            return None;
16758        }
16759
16760        let snapshot = cursor_buffer.read(cx).snapshot();
16761        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16762        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16763        let prepare_rename = provider
16764            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16765            .unwrap_or_else(|| Task::ready(Ok(None)));
16766        drop(snapshot);
16767
16768        Some(cx.spawn_in(window, async move |this, cx| {
16769            let rename_range = if let Some(range) = prepare_rename.await? {
16770                Some(range)
16771            } else {
16772                this.update(cx, |this, cx| {
16773                    let buffer = this.buffer.read(cx).snapshot(cx);
16774                    let mut buffer_highlights = this
16775                        .document_highlights_for_position(selection.head(), &buffer)
16776                        .filter(|highlight| {
16777                            highlight.start.excerpt_id == selection.head().excerpt_id
16778                                && highlight.end.excerpt_id == selection.head().excerpt_id
16779                        });
16780                    buffer_highlights
16781                        .next()
16782                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16783                })?
16784            };
16785            if let Some(rename_range) = rename_range {
16786                this.update_in(cx, |this, window, cx| {
16787                    let snapshot = cursor_buffer.read(cx).snapshot();
16788                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16789                    let cursor_offset_in_rename_range =
16790                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16791                    let cursor_offset_in_rename_range_end =
16792                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16793
16794                    this.take_rename(false, window, cx);
16795                    let buffer = this.buffer.read(cx).read(cx);
16796                    let cursor_offset = selection.head().to_offset(&buffer);
16797                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16798                    let rename_end = rename_start + rename_buffer_range.len();
16799                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16800                    let mut old_highlight_id = None;
16801                    let old_name: Arc<str> = buffer
16802                        .chunks(rename_start..rename_end, true)
16803                        .map(|chunk| {
16804                            if old_highlight_id.is_none() {
16805                                old_highlight_id = chunk.syntax_highlight_id;
16806                            }
16807                            chunk.text
16808                        })
16809                        .collect::<String>()
16810                        .into();
16811
16812                    drop(buffer);
16813
16814                    // Position the selection in the rename editor so that it matches the current selection.
16815                    this.show_local_selections = false;
16816                    let rename_editor = cx.new(|cx| {
16817                        let mut editor = Editor::single_line(window, cx);
16818                        editor.buffer.update(cx, |buffer, cx| {
16819                            buffer.edit([(0..0, old_name.clone())], None, cx)
16820                        });
16821                        let rename_selection_range = match cursor_offset_in_rename_range
16822                            .cmp(&cursor_offset_in_rename_range_end)
16823                        {
16824                            Ordering::Equal => {
16825                                editor.select_all(&SelectAll, window, cx);
16826                                return editor;
16827                            }
16828                            Ordering::Less => {
16829                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16830                            }
16831                            Ordering::Greater => {
16832                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16833                            }
16834                        };
16835                        if rename_selection_range.end > old_name.len() {
16836                            editor.select_all(&SelectAll, window, cx);
16837                        } else {
16838                            editor.change_selections(Default::default(), window, cx, |s| {
16839                                s.select_ranges([rename_selection_range]);
16840                            });
16841                        }
16842                        editor
16843                    });
16844                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16845                        if e == &EditorEvent::Focused {
16846                            cx.emit(EditorEvent::FocusedIn)
16847                        }
16848                    })
16849                    .detach();
16850
16851                    let write_highlights =
16852                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16853                    let read_highlights =
16854                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16855                    let ranges = write_highlights
16856                        .iter()
16857                        .flat_map(|(_, ranges)| ranges.iter())
16858                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16859                        .cloned()
16860                        .collect();
16861
16862                    this.highlight_text::<Rename>(
16863                        ranges,
16864                        HighlightStyle {
16865                            fade_out: Some(0.6),
16866                            ..Default::default()
16867                        },
16868                        cx,
16869                    );
16870                    let rename_focus_handle = rename_editor.focus_handle(cx);
16871                    window.focus(&rename_focus_handle);
16872                    let block_id = this.insert_blocks(
16873                        [BlockProperties {
16874                            style: BlockStyle::Flex,
16875                            placement: BlockPlacement::Below(range.start),
16876                            height: Some(1),
16877                            render: Arc::new({
16878                                let rename_editor = rename_editor.clone();
16879                                move |cx: &mut BlockContext| {
16880                                    let mut text_style = cx.editor_style.text.clone();
16881                                    if let Some(highlight_style) = old_highlight_id
16882                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16883                                    {
16884                                        text_style = text_style.highlight(highlight_style);
16885                                    }
16886                                    div()
16887                                        .block_mouse_except_scroll()
16888                                        .pl(cx.anchor_x)
16889                                        .child(EditorElement::new(
16890                                            &rename_editor,
16891                                            EditorStyle {
16892                                                background: cx.theme().system().transparent,
16893                                                local_player: cx.editor_style.local_player,
16894                                                text: text_style,
16895                                                scrollbar_width: cx.editor_style.scrollbar_width,
16896                                                syntax: cx.editor_style.syntax.clone(),
16897                                                status: cx.editor_style.status.clone(),
16898                                                inlay_hints_style: HighlightStyle {
16899                                                    font_weight: Some(FontWeight::BOLD),
16900                                                    ..make_inlay_hints_style(cx.app)
16901                                                },
16902                                                edit_prediction_styles: make_suggestion_styles(
16903                                                    cx.app,
16904                                                ),
16905                                                ..EditorStyle::default()
16906                                            },
16907                                        ))
16908                                        .into_any_element()
16909                                }
16910                            }),
16911                            priority: 0,
16912                        }],
16913                        Some(Autoscroll::fit()),
16914                        cx,
16915                    )[0];
16916                    this.pending_rename = Some(RenameState {
16917                        range,
16918                        old_name,
16919                        editor: rename_editor,
16920                        block_id,
16921                    });
16922                })?;
16923            }
16924
16925            Ok(())
16926        }))
16927    }
16928
16929    pub fn confirm_rename(
16930        &mut self,
16931        _: &ConfirmRename,
16932        window: &mut Window,
16933        cx: &mut Context<Self>,
16934    ) -> Option<Task<Result<()>>> {
16935        let rename = self.take_rename(false, window, cx)?;
16936        let workspace = self.workspace()?.downgrade();
16937        let (buffer, start) = self
16938            .buffer
16939            .read(cx)
16940            .text_anchor_for_position(rename.range.start, cx)?;
16941        let (end_buffer, _) = self
16942            .buffer
16943            .read(cx)
16944            .text_anchor_for_position(rename.range.end, cx)?;
16945        if buffer != end_buffer {
16946            return None;
16947        }
16948
16949        let old_name = rename.old_name;
16950        let new_name = rename.editor.read(cx).text(cx);
16951
16952        let rename = self.semantics_provider.as_ref()?.perform_rename(
16953            &buffer,
16954            start,
16955            new_name.clone(),
16956            cx,
16957        )?;
16958
16959        Some(cx.spawn_in(window, async move |editor, cx| {
16960            let project_transaction = rename.await?;
16961            Self::open_project_transaction(
16962                &editor,
16963                workspace,
16964                project_transaction,
16965                format!("Rename: {}{}", old_name, new_name),
16966                cx,
16967            )
16968            .await?;
16969
16970            editor.update(cx, |editor, cx| {
16971                editor.refresh_document_highlights(cx);
16972            })?;
16973            Ok(())
16974        }))
16975    }
16976
16977    fn take_rename(
16978        &mut self,
16979        moving_cursor: bool,
16980        window: &mut Window,
16981        cx: &mut Context<Self>,
16982    ) -> Option<RenameState> {
16983        let rename = self.pending_rename.take()?;
16984        if rename.editor.focus_handle(cx).is_focused(window) {
16985            window.focus(&self.focus_handle);
16986        }
16987
16988        self.remove_blocks(
16989            [rename.block_id].into_iter().collect(),
16990            Some(Autoscroll::fit()),
16991            cx,
16992        );
16993        self.clear_highlights::<Rename>(cx);
16994        self.show_local_selections = true;
16995
16996        if moving_cursor {
16997            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16998                editor.selections.newest::<usize>(cx).head()
16999            });
17000
17001            // Update the selection to match the position of the selection inside
17002            // the rename editor.
17003            let snapshot = self.buffer.read(cx).read(cx);
17004            let rename_range = rename.range.to_offset(&snapshot);
17005            let cursor_in_editor = snapshot
17006                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17007                .min(rename_range.end);
17008            drop(snapshot);
17009
17010            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17011                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17012            });
17013        } else {
17014            self.refresh_document_highlights(cx);
17015        }
17016
17017        Some(rename)
17018    }
17019
17020    pub fn pending_rename(&self) -> Option<&RenameState> {
17021        self.pending_rename.as_ref()
17022    }
17023
17024    fn format(
17025        &mut self,
17026        _: &Format,
17027        window: &mut Window,
17028        cx: &mut Context<Self>,
17029    ) -> Option<Task<Result<()>>> {
17030        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17031
17032        let project = match &self.project {
17033            Some(project) => project.clone(),
17034            None => return None,
17035        };
17036
17037        Some(self.perform_format(
17038            project,
17039            FormatTrigger::Manual,
17040            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17041            window,
17042            cx,
17043        ))
17044    }
17045
17046    fn format_selections(
17047        &mut self,
17048        _: &FormatSelections,
17049        window: &mut Window,
17050        cx: &mut Context<Self>,
17051    ) -> Option<Task<Result<()>>> {
17052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17053
17054        let project = match &self.project {
17055            Some(project) => project.clone(),
17056            None => return None,
17057        };
17058
17059        let ranges = self
17060            .selections
17061            .all_adjusted(cx)
17062            .into_iter()
17063            .map(|selection| selection.range())
17064            .collect_vec();
17065
17066        Some(self.perform_format(
17067            project,
17068            FormatTrigger::Manual,
17069            FormatTarget::Ranges(ranges),
17070            window,
17071            cx,
17072        ))
17073    }
17074
17075    fn perform_format(
17076        &mut self,
17077        project: Entity<Project>,
17078        trigger: FormatTrigger,
17079        target: FormatTarget,
17080        window: &mut Window,
17081        cx: &mut Context<Self>,
17082    ) -> Task<Result<()>> {
17083        let buffer = self.buffer.clone();
17084        let (buffers, target) = match target {
17085            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17086            FormatTarget::Ranges(selection_ranges) => {
17087                let multi_buffer = buffer.read(cx);
17088                let snapshot = multi_buffer.read(cx);
17089                let mut buffers = HashSet::default();
17090                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17091                    BTreeMap::new();
17092                for selection_range in selection_ranges {
17093                    for (buffer, buffer_range, _) in
17094                        snapshot.range_to_buffer_ranges(selection_range)
17095                    {
17096                        let buffer_id = buffer.remote_id();
17097                        let start = buffer.anchor_before(buffer_range.start);
17098                        let end = buffer.anchor_after(buffer_range.end);
17099                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17100                        buffer_id_to_ranges
17101                            .entry(buffer_id)
17102                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17103                            .or_insert_with(|| vec![start..end]);
17104                    }
17105                }
17106                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17107            }
17108        };
17109
17110        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17111        let selections_prev = transaction_id_prev
17112            .and_then(|transaction_id_prev| {
17113                // default to selections as they were after the last edit, if we have them,
17114                // instead of how they are now.
17115                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17116                // will take you back to where you made the last edit, instead of staying where you scrolled
17117                self.selection_history
17118                    .transaction(transaction_id_prev)
17119                    .map(|t| t.0.clone())
17120            })
17121            .unwrap_or_else(|| self.selections.disjoint_anchors());
17122
17123        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17124        let format = project.update(cx, |project, cx| {
17125            project.format(buffers, target, true, trigger, cx)
17126        });
17127
17128        cx.spawn_in(window, async move |editor, cx| {
17129            let transaction = futures::select_biased! {
17130                transaction = format.log_err().fuse() => transaction,
17131                () = timeout => {
17132                    log::warn!("timed out waiting for formatting");
17133                    None
17134                }
17135            };
17136
17137            buffer
17138                .update(cx, |buffer, cx| {
17139                    if let Some(transaction) = transaction
17140                        && !buffer.is_singleton()
17141                    {
17142                        buffer.push_transaction(&transaction.0, cx);
17143                    }
17144                    cx.notify();
17145                })
17146                .ok();
17147
17148            if let Some(transaction_id_now) =
17149                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17150            {
17151                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17152                if has_new_transaction {
17153                    _ = editor.update(cx, |editor, _| {
17154                        editor
17155                            .selection_history
17156                            .insert_transaction(transaction_id_now, selections_prev);
17157                    });
17158                }
17159            }
17160
17161            Ok(())
17162        })
17163    }
17164
17165    fn organize_imports(
17166        &mut self,
17167        _: &OrganizeImports,
17168        window: &mut Window,
17169        cx: &mut Context<Self>,
17170    ) -> Option<Task<Result<()>>> {
17171        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17172        let project = match &self.project {
17173            Some(project) => project.clone(),
17174            None => return None,
17175        };
17176        Some(self.perform_code_action_kind(
17177            project,
17178            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17179            window,
17180            cx,
17181        ))
17182    }
17183
17184    fn perform_code_action_kind(
17185        &mut self,
17186        project: Entity<Project>,
17187        kind: CodeActionKind,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) -> Task<Result<()>> {
17191        let buffer = self.buffer.clone();
17192        let buffers = buffer.read(cx).all_buffers();
17193        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17194        let apply_action = project.update(cx, |project, cx| {
17195            project.apply_code_action_kind(buffers, kind, true, cx)
17196        });
17197        cx.spawn_in(window, async move |_, cx| {
17198            let transaction = futures::select_biased! {
17199                () = timeout => {
17200                    log::warn!("timed out waiting for executing code action");
17201                    None
17202                }
17203                transaction = apply_action.log_err().fuse() => transaction,
17204            };
17205            buffer
17206                .update(cx, |buffer, cx| {
17207                    // check if we need this
17208                    if let Some(transaction) = transaction
17209                        && !buffer.is_singleton()
17210                    {
17211                        buffer.push_transaction(&transaction.0, cx);
17212                    }
17213                    cx.notify();
17214                })
17215                .ok();
17216            Ok(())
17217        })
17218    }
17219
17220    pub fn restart_language_server(
17221        &mut self,
17222        _: &RestartLanguageServer,
17223        _: &mut Window,
17224        cx: &mut Context<Self>,
17225    ) {
17226        if let Some(project) = self.project.clone() {
17227            self.buffer.update(cx, |multi_buffer, cx| {
17228                project.update(cx, |project, cx| {
17229                    project.restart_language_servers_for_buffers(
17230                        multi_buffer.all_buffers().into_iter().collect(),
17231                        HashSet::default(),
17232                        cx,
17233                    );
17234                });
17235            })
17236        }
17237    }
17238
17239    pub fn stop_language_server(
17240        &mut self,
17241        _: &StopLanguageServer,
17242        _: &mut Window,
17243        cx: &mut Context<Self>,
17244    ) {
17245        if let Some(project) = self.project.clone() {
17246            self.buffer.update(cx, |multi_buffer, cx| {
17247                project.update(cx, |project, cx| {
17248                    project.stop_language_servers_for_buffers(
17249                        multi_buffer.all_buffers().into_iter().collect(),
17250                        HashSet::default(),
17251                        cx,
17252                    );
17253                    cx.emit(project::Event::RefreshInlayHints);
17254                });
17255            });
17256        }
17257    }
17258
17259    fn cancel_language_server_work(
17260        workspace: &mut Workspace,
17261        _: &actions::CancelLanguageServerWork,
17262        _: &mut Window,
17263        cx: &mut Context<Workspace>,
17264    ) {
17265        let project = workspace.project();
17266        let buffers = workspace
17267            .active_item(cx)
17268            .and_then(|item| item.act_as::<Editor>(cx))
17269            .map_or(HashSet::default(), |editor| {
17270                editor.read(cx).buffer.read(cx).all_buffers()
17271            });
17272        project.update(cx, |project, cx| {
17273            project.cancel_language_server_work_for_buffers(buffers, cx);
17274        });
17275    }
17276
17277    fn show_character_palette(
17278        &mut self,
17279        _: &ShowCharacterPalette,
17280        window: &mut Window,
17281        _: &mut Context<Self>,
17282    ) {
17283        window.show_character_palette();
17284    }
17285
17286    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17287        if !self.diagnostics_enabled() {
17288            return;
17289        }
17290
17291        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17292            let buffer = self.buffer.read(cx).snapshot(cx);
17293            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17294            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17295            let is_valid = buffer
17296                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17297                .any(|entry| {
17298                    entry.diagnostic.is_primary
17299                        && !entry.range.is_empty()
17300                        && entry.range.start == primary_range_start
17301                        && entry.diagnostic.message == active_diagnostics.active_message
17302                });
17303
17304            if !is_valid {
17305                self.dismiss_diagnostics(cx);
17306            }
17307        }
17308    }
17309
17310    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17311        match &self.active_diagnostics {
17312            ActiveDiagnostic::Group(group) => Some(group),
17313            _ => None,
17314        }
17315    }
17316
17317    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17318        if !self.diagnostics_enabled() {
17319            return;
17320        }
17321        self.dismiss_diagnostics(cx);
17322        self.active_diagnostics = ActiveDiagnostic::All;
17323    }
17324
17325    fn activate_diagnostics(
17326        &mut self,
17327        buffer_id: BufferId,
17328        diagnostic: DiagnosticEntry<usize>,
17329        window: &mut Window,
17330        cx: &mut Context<Self>,
17331    ) {
17332        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17333            return;
17334        }
17335        self.dismiss_diagnostics(cx);
17336        let snapshot = self.snapshot(window, cx);
17337        let buffer = self.buffer.read(cx).snapshot(cx);
17338        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17339            return;
17340        };
17341
17342        let diagnostic_group = buffer
17343            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17344            .collect::<Vec<_>>();
17345
17346        let blocks =
17347            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17348
17349        let blocks = self.display_map.update(cx, |display_map, cx| {
17350            display_map.insert_blocks(blocks, cx).into_iter().collect()
17351        });
17352        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17353            active_range: buffer.anchor_before(diagnostic.range.start)
17354                ..buffer.anchor_after(diagnostic.range.end),
17355            active_message: diagnostic.diagnostic.message.clone(),
17356            group_id: diagnostic.diagnostic.group_id,
17357            blocks,
17358        });
17359        cx.notify();
17360    }
17361
17362    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17363        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17364            return;
17365        };
17366
17367        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17368        if let ActiveDiagnostic::Group(group) = prev {
17369            self.display_map.update(cx, |display_map, cx| {
17370                display_map.remove_blocks(group.blocks, cx);
17371            });
17372            cx.notify();
17373        }
17374    }
17375
17376    /// Disable inline diagnostics rendering for this editor.
17377    pub fn disable_inline_diagnostics(&mut self) {
17378        self.inline_diagnostics_enabled = false;
17379        self.inline_diagnostics_update = Task::ready(());
17380        self.inline_diagnostics.clear();
17381    }
17382
17383    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17384        self.diagnostics_enabled = false;
17385        self.dismiss_diagnostics(cx);
17386        self.inline_diagnostics_update = Task::ready(());
17387        self.inline_diagnostics.clear();
17388    }
17389
17390    pub fn disable_word_completions(&mut self) {
17391        self.word_completions_enabled = false;
17392    }
17393
17394    pub fn diagnostics_enabled(&self) -> bool {
17395        self.diagnostics_enabled && self.mode.is_full()
17396    }
17397
17398    pub fn inline_diagnostics_enabled(&self) -> bool {
17399        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17400    }
17401
17402    pub fn show_inline_diagnostics(&self) -> bool {
17403        self.show_inline_diagnostics
17404    }
17405
17406    pub fn toggle_inline_diagnostics(
17407        &mut self,
17408        _: &ToggleInlineDiagnostics,
17409        window: &mut Window,
17410        cx: &mut Context<Editor>,
17411    ) {
17412        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17413        self.refresh_inline_diagnostics(false, window, cx);
17414    }
17415
17416    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17417        self.diagnostics_max_severity = severity;
17418        self.display_map.update(cx, |display_map, _| {
17419            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17420        });
17421    }
17422
17423    pub fn toggle_diagnostics(
17424        &mut self,
17425        _: &ToggleDiagnostics,
17426        window: &mut Window,
17427        cx: &mut Context<Editor>,
17428    ) {
17429        if !self.diagnostics_enabled() {
17430            return;
17431        }
17432
17433        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17434            EditorSettings::get_global(cx)
17435                .diagnostics_max_severity
17436                .filter(|severity| severity != &DiagnosticSeverity::Off)
17437                .unwrap_or(DiagnosticSeverity::Hint)
17438        } else {
17439            DiagnosticSeverity::Off
17440        };
17441        self.set_max_diagnostics_severity(new_severity, cx);
17442        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17443            self.active_diagnostics = ActiveDiagnostic::None;
17444            self.inline_diagnostics_update = Task::ready(());
17445            self.inline_diagnostics.clear();
17446        } else {
17447            self.refresh_inline_diagnostics(false, window, cx);
17448        }
17449
17450        cx.notify();
17451    }
17452
17453    pub fn toggle_minimap(
17454        &mut self,
17455        _: &ToggleMinimap,
17456        window: &mut Window,
17457        cx: &mut Context<Editor>,
17458    ) {
17459        if self.supports_minimap(cx) {
17460            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17461        }
17462    }
17463
17464    fn refresh_inline_diagnostics(
17465        &mut self,
17466        debounce: bool,
17467        window: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        let max_severity = ProjectSettings::get_global(cx)
17471            .diagnostics
17472            .inline
17473            .max_severity
17474            .unwrap_or(self.diagnostics_max_severity);
17475
17476        if !self.inline_diagnostics_enabled()
17477            || !self.show_inline_diagnostics
17478            || max_severity == DiagnosticSeverity::Off
17479        {
17480            self.inline_diagnostics_update = Task::ready(());
17481            self.inline_diagnostics.clear();
17482            return;
17483        }
17484
17485        let debounce_ms = ProjectSettings::get_global(cx)
17486            .diagnostics
17487            .inline
17488            .update_debounce_ms;
17489        let debounce = if debounce && debounce_ms > 0 {
17490            Some(Duration::from_millis(debounce_ms))
17491        } else {
17492            None
17493        };
17494        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17495            if let Some(debounce) = debounce {
17496                cx.background_executor().timer(debounce).await;
17497            }
17498            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17499                editor
17500                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17501                    .ok()
17502            }) else {
17503                return;
17504            };
17505
17506            let new_inline_diagnostics = cx
17507                .background_spawn(async move {
17508                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17509                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17510                        let message = diagnostic_entry
17511                            .diagnostic
17512                            .message
17513                            .split_once('\n')
17514                            .map(|(line, _)| line)
17515                            .map(SharedString::new)
17516                            .unwrap_or_else(|| {
17517                                SharedString::from(diagnostic_entry.diagnostic.message)
17518                            });
17519                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17520                        let (Ok(i) | Err(i)) = inline_diagnostics
17521                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17522                        inline_diagnostics.insert(
17523                            i,
17524                            (
17525                                start_anchor,
17526                                InlineDiagnostic {
17527                                    message,
17528                                    group_id: diagnostic_entry.diagnostic.group_id,
17529                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17530                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17531                                    severity: diagnostic_entry.diagnostic.severity,
17532                                },
17533                            ),
17534                        );
17535                    }
17536                    inline_diagnostics
17537                })
17538                .await;
17539
17540            editor
17541                .update(cx, |editor, cx| {
17542                    editor.inline_diagnostics = new_inline_diagnostics;
17543                    cx.notify();
17544                })
17545                .ok();
17546        });
17547    }
17548
17549    fn pull_diagnostics(
17550        &mut self,
17551        buffer_id: Option<BufferId>,
17552        window: &Window,
17553        cx: &mut Context<Self>,
17554    ) -> Option<()> {
17555        if !self.mode().is_full() {
17556            return None;
17557        }
17558        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17559            .diagnostics
17560            .lsp_pull_diagnostics;
17561        if !pull_diagnostics_settings.enabled {
17562            return None;
17563        }
17564        let project = self.project()?.downgrade();
17565        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17566        let mut buffers = self.buffer.read(cx).all_buffers();
17567        if let Some(buffer_id) = buffer_id {
17568            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17569        }
17570
17571        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17572            cx.background_executor().timer(debounce).await;
17573
17574            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17575                buffers
17576                    .into_iter()
17577                    .filter_map(|buffer| {
17578                        project
17579                            .update(cx, |project, cx| {
17580                                project.lsp_store().update(cx, |lsp_store, cx| {
17581                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17582                                })
17583                            })
17584                            .ok()
17585                    })
17586                    .collect::<FuturesUnordered<_>>()
17587            }) else {
17588                return;
17589            };
17590
17591            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17592                match pull_task {
17593                    Ok(()) => {
17594                        if editor
17595                            .update_in(cx, |editor, window, cx| {
17596                                editor.update_diagnostics_state(window, cx);
17597                            })
17598                            .is_err()
17599                        {
17600                            return;
17601                        }
17602                    }
17603                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17604                }
17605            }
17606        });
17607
17608        Some(())
17609    }
17610
17611    pub fn set_selections_from_remote(
17612        &mut self,
17613        selections: Vec<Selection<Anchor>>,
17614        pending_selection: Option<Selection<Anchor>>,
17615        window: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        let old_cursor_position = self.selections.newest_anchor().head();
17619        self.selections.change_with(cx, |s| {
17620            s.select_anchors(selections);
17621            if let Some(pending_selection) = pending_selection {
17622                s.set_pending(pending_selection, SelectMode::Character);
17623            } else {
17624                s.clear_pending();
17625            }
17626        });
17627        self.selections_did_change(
17628            false,
17629            &old_cursor_position,
17630            SelectionEffects::default(),
17631            window,
17632            cx,
17633        );
17634    }
17635
17636    pub fn transact(
17637        &mut self,
17638        window: &mut Window,
17639        cx: &mut Context<Self>,
17640        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17641    ) -> Option<TransactionId> {
17642        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17643            this.start_transaction_at(Instant::now(), window, cx);
17644            update(this, window, cx);
17645            this.end_transaction_at(Instant::now(), cx)
17646        })
17647    }
17648
17649    pub fn start_transaction_at(
17650        &mut self,
17651        now: Instant,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Option<TransactionId> {
17655        self.end_selection(window, cx);
17656        if let Some(tx_id) = self
17657            .buffer
17658            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17659        {
17660            self.selection_history
17661                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17662            cx.emit(EditorEvent::TransactionBegun {
17663                transaction_id: tx_id,
17664            });
17665            Some(tx_id)
17666        } else {
17667            None
17668        }
17669    }
17670
17671    pub fn end_transaction_at(
17672        &mut self,
17673        now: Instant,
17674        cx: &mut Context<Self>,
17675    ) -> Option<TransactionId> {
17676        if let Some(transaction_id) = self
17677            .buffer
17678            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17679        {
17680            if let Some((_, end_selections)) =
17681                self.selection_history.transaction_mut(transaction_id)
17682            {
17683                *end_selections = Some(self.selections.disjoint_anchors());
17684            } else {
17685                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17686            }
17687
17688            cx.emit(EditorEvent::Edited { transaction_id });
17689            Some(transaction_id)
17690        } else {
17691            None
17692        }
17693    }
17694
17695    pub fn modify_transaction_selection_history(
17696        &mut self,
17697        transaction_id: TransactionId,
17698        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17699    ) -> bool {
17700        self.selection_history
17701            .transaction_mut(transaction_id)
17702            .map(modify)
17703            .is_some()
17704    }
17705
17706    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17707        if self.selection_mark_mode {
17708            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17709                s.move_with(|_, sel| {
17710                    sel.collapse_to(sel.head(), SelectionGoal::None);
17711                });
17712            })
17713        }
17714        self.selection_mark_mode = true;
17715        cx.notify();
17716    }
17717
17718    pub fn swap_selection_ends(
17719        &mut self,
17720        _: &actions::SwapSelectionEnds,
17721        window: &mut Window,
17722        cx: &mut Context<Self>,
17723    ) {
17724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17725            s.move_with(|_, sel| {
17726                if sel.start != sel.end {
17727                    sel.reversed = !sel.reversed
17728                }
17729            });
17730        });
17731        self.request_autoscroll(Autoscroll::newest(), cx);
17732        cx.notify();
17733    }
17734
17735    pub fn toggle_focus(
17736        workspace: &mut Workspace,
17737        _: &actions::ToggleFocus,
17738        window: &mut Window,
17739        cx: &mut Context<Workspace>,
17740    ) {
17741        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17742            return;
17743        };
17744        workspace.activate_item(&item, true, true, window, cx);
17745    }
17746
17747    pub fn toggle_fold(
17748        &mut self,
17749        _: &actions::ToggleFold,
17750        window: &mut Window,
17751        cx: &mut Context<Self>,
17752    ) {
17753        if self.is_singleton(cx) {
17754            let selection = self.selections.newest::<Point>(cx);
17755
17756            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17757            let range = if selection.is_empty() {
17758                let point = selection.head().to_display_point(&display_map);
17759                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17760                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17761                    .to_point(&display_map);
17762                start..end
17763            } else {
17764                selection.range()
17765            };
17766            if display_map.folds_in_range(range).next().is_some() {
17767                self.unfold_lines(&Default::default(), window, cx)
17768            } else {
17769                self.fold(&Default::default(), window, cx)
17770            }
17771        } else {
17772            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17773            let buffer_ids: HashSet<_> = self
17774                .selections
17775                .disjoint_anchor_ranges()
17776                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17777                .collect();
17778
17779            let should_unfold = buffer_ids
17780                .iter()
17781                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17782
17783            for buffer_id in buffer_ids {
17784                if should_unfold {
17785                    self.unfold_buffer(buffer_id, cx);
17786                } else {
17787                    self.fold_buffer(buffer_id, cx);
17788                }
17789            }
17790        }
17791    }
17792
17793    pub fn toggle_fold_recursive(
17794        &mut self,
17795        _: &actions::ToggleFoldRecursive,
17796        window: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) {
17799        let selection = self.selections.newest::<Point>(cx);
17800
17801        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17802        let range = if selection.is_empty() {
17803            let point = selection.head().to_display_point(&display_map);
17804            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17805            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17806                .to_point(&display_map);
17807            start..end
17808        } else {
17809            selection.range()
17810        };
17811        if display_map.folds_in_range(range).next().is_some() {
17812            self.unfold_recursive(&Default::default(), window, cx)
17813        } else {
17814            self.fold_recursive(&Default::default(), window, cx)
17815        }
17816    }
17817
17818    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17819        if self.is_singleton(cx) {
17820            let mut to_fold = Vec::new();
17821            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17822            let selections = self.selections.all_adjusted(cx);
17823
17824            for selection in selections {
17825                let range = selection.range().sorted();
17826                let buffer_start_row = range.start.row;
17827
17828                if range.start.row != range.end.row {
17829                    let mut found = false;
17830                    let mut row = range.start.row;
17831                    while row <= range.end.row {
17832                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17833                        {
17834                            found = true;
17835                            row = crease.range().end.row + 1;
17836                            to_fold.push(crease);
17837                        } else {
17838                            row += 1
17839                        }
17840                    }
17841                    if found {
17842                        continue;
17843                    }
17844                }
17845
17846                for row in (0..=range.start.row).rev() {
17847                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17848                        && crease.range().end.row >= buffer_start_row
17849                    {
17850                        to_fold.push(crease);
17851                        if row <= range.start.row {
17852                            break;
17853                        }
17854                    }
17855                }
17856            }
17857
17858            self.fold_creases(to_fold, true, window, cx);
17859        } else {
17860            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17861            let buffer_ids = self
17862                .selections
17863                .disjoint_anchor_ranges()
17864                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17865                .collect::<HashSet<_>>();
17866            for buffer_id in buffer_ids {
17867                self.fold_buffer(buffer_id, cx);
17868            }
17869        }
17870    }
17871
17872    pub fn toggle_fold_all(
17873        &mut self,
17874        _: &actions::ToggleFoldAll,
17875        window: &mut Window,
17876        cx: &mut Context<Self>,
17877    ) {
17878        if self.buffer.read(cx).is_singleton() {
17879            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17880            let has_folds = display_map
17881                .folds_in_range(0..display_map.buffer_snapshot.len())
17882                .next()
17883                .is_some();
17884
17885            if has_folds {
17886                self.unfold_all(&actions::UnfoldAll, window, cx);
17887            } else {
17888                self.fold_all(&actions::FoldAll, window, cx);
17889            }
17890        } else {
17891            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17892            let should_unfold = buffer_ids
17893                .iter()
17894                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17895
17896            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17897                editor
17898                    .update_in(cx, |editor, _, cx| {
17899                        for buffer_id in buffer_ids {
17900                            if should_unfold {
17901                                editor.unfold_buffer(buffer_id, cx);
17902                            } else {
17903                                editor.fold_buffer(buffer_id, cx);
17904                            }
17905                        }
17906                    })
17907                    .ok();
17908            });
17909        }
17910    }
17911
17912    fn fold_at_level(
17913        &mut self,
17914        fold_at: &FoldAtLevel,
17915        window: &mut Window,
17916        cx: &mut Context<Self>,
17917    ) {
17918        if !self.buffer.read(cx).is_singleton() {
17919            return;
17920        }
17921
17922        let fold_at_level = fold_at.0;
17923        let snapshot = self.buffer.read(cx).snapshot(cx);
17924        let mut to_fold = Vec::new();
17925        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17926
17927        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17928            while start_row < end_row {
17929                match self
17930                    .snapshot(window, cx)
17931                    .crease_for_buffer_row(MultiBufferRow(start_row))
17932                {
17933                    Some(crease) => {
17934                        let nested_start_row = crease.range().start.row + 1;
17935                        let nested_end_row = crease.range().end.row;
17936
17937                        if current_level < fold_at_level {
17938                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17939                        } else if current_level == fold_at_level {
17940                            to_fold.push(crease);
17941                        }
17942
17943                        start_row = nested_end_row + 1;
17944                    }
17945                    None => start_row += 1,
17946                }
17947            }
17948        }
17949
17950        self.fold_creases(to_fold, true, window, cx);
17951    }
17952
17953    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17954        if self.buffer.read(cx).is_singleton() {
17955            let mut fold_ranges = Vec::new();
17956            let snapshot = self.buffer.read(cx).snapshot(cx);
17957
17958            for row in 0..snapshot.max_row().0 {
17959                if let Some(foldable_range) = self
17960                    .snapshot(window, cx)
17961                    .crease_for_buffer_row(MultiBufferRow(row))
17962                {
17963                    fold_ranges.push(foldable_range);
17964                }
17965            }
17966
17967            self.fold_creases(fold_ranges, true, window, cx);
17968        } else {
17969            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17970                editor
17971                    .update_in(cx, |editor, _, cx| {
17972                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17973                            editor.fold_buffer(buffer_id, cx);
17974                        }
17975                    })
17976                    .ok();
17977            });
17978        }
17979    }
17980
17981    pub fn fold_function_bodies(
17982        &mut self,
17983        _: &actions::FoldFunctionBodies,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        let snapshot = self.buffer.read(cx).snapshot(cx);
17988
17989        let ranges = snapshot
17990            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17991            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17992            .collect::<Vec<_>>();
17993
17994        let creases = ranges
17995            .into_iter()
17996            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17997            .collect();
17998
17999        self.fold_creases(creases, true, window, cx);
18000    }
18001
18002    pub fn fold_recursive(
18003        &mut self,
18004        _: &actions::FoldRecursive,
18005        window: &mut Window,
18006        cx: &mut Context<Self>,
18007    ) {
18008        let mut to_fold = Vec::new();
18009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18010        let selections = self.selections.all_adjusted(cx);
18011
18012        for selection in selections {
18013            let range = selection.range().sorted();
18014            let buffer_start_row = range.start.row;
18015
18016            if range.start.row != range.end.row {
18017                let mut found = false;
18018                for row in range.start.row..=range.end.row {
18019                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18020                        found = true;
18021                        to_fold.push(crease);
18022                    }
18023                }
18024                if found {
18025                    continue;
18026                }
18027            }
18028
18029            for row in (0..=range.start.row).rev() {
18030                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18031                    if crease.range().end.row >= buffer_start_row {
18032                        to_fold.push(crease);
18033                    } else {
18034                        break;
18035                    }
18036                }
18037            }
18038        }
18039
18040        self.fold_creases(to_fold, true, window, cx);
18041    }
18042
18043    pub fn fold_at(
18044        &mut self,
18045        buffer_row: MultiBufferRow,
18046        window: &mut Window,
18047        cx: &mut Context<Self>,
18048    ) {
18049        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18050
18051        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18052            let autoscroll = self
18053                .selections
18054                .all::<Point>(cx)
18055                .iter()
18056                .any(|selection| crease.range().overlaps(&selection.range()));
18057
18058            self.fold_creases(vec![crease], autoscroll, window, cx);
18059        }
18060    }
18061
18062    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18063        if self.is_singleton(cx) {
18064            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18065            let buffer = &display_map.buffer_snapshot;
18066            let selections = self.selections.all::<Point>(cx);
18067            let ranges = selections
18068                .iter()
18069                .map(|s| {
18070                    let range = s.display_range(&display_map).sorted();
18071                    let mut start = range.start.to_point(&display_map);
18072                    let mut end = range.end.to_point(&display_map);
18073                    start.column = 0;
18074                    end.column = buffer.line_len(MultiBufferRow(end.row));
18075                    start..end
18076                })
18077                .collect::<Vec<_>>();
18078
18079            self.unfold_ranges(&ranges, true, true, cx);
18080        } else {
18081            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18082            let buffer_ids = self
18083                .selections
18084                .disjoint_anchor_ranges()
18085                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18086                .collect::<HashSet<_>>();
18087            for buffer_id in buffer_ids {
18088                self.unfold_buffer(buffer_id, cx);
18089            }
18090        }
18091    }
18092
18093    pub fn unfold_recursive(
18094        &mut self,
18095        _: &UnfoldRecursive,
18096        _window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) {
18099        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18100        let selections = self.selections.all::<Point>(cx);
18101        let ranges = selections
18102            .iter()
18103            .map(|s| {
18104                let mut range = s.display_range(&display_map).sorted();
18105                *range.start.column_mut() = 0;
18106                *range.end.column_mut() = display_map.line_len(range.end.row());
18107                let start = range.start.to_point(&display_map);
18108                let end = range.end.to_point(&display_map);
18109                start..end
18110            })
18111            .collect::<Vec<_>>();
18112
18113        self.unfold_ranges(&ranges, true, true, cx);
18114    }
18115
18116    pub fn unfold_at(
18117        &mut self,
18118        buffer_row: MultiBufferRow,
18119        _window: &mut Window,
18120        cx: &mut Context<Self>,
18121    ) {
18122        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18123
18124        let intersection_range = Point::new(buffer_row.0, 0)
18125            ..Point::new(
18126                buffer_row.0,
18127                display_map.buffer_snapshot.line_len(buffer_row),
18128            );
18129
18130        let autoscroll = self
18131            .selections
18132            .all::<Point>(cx)
18133            .iter()
18134            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18135
18136        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18137    }
18138
18139    pub fn unfold_all(
18140        &mut self,
18141        _: &actions::UnfoldAll,
18142        _window: &mut Window,
18143        cx: &mut Context<Self>,
18144    ) {
18145        if self.buffer.read(cx).is_singleton() {
18146            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18147            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
18148        } else {
18149            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18150                editor
18151                    .update(cx, |editor, cx| {
18152                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18153                            editor.unfold_buffer(buffer_id, cx);
18154                        }
18155                    })
18156                    .ok();
18157            });
18158        }
18159    }
18160
18161    pub fn fold_selected_ranges(
18162        &mut self,
18163        _: &FoldSelectedRanges,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) {
18167        let selections = self.selections.all_adjusted(cx);
18168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18169        let ranges = selections
18170            .into_iter()
18171            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18172            .collect::<Vec<_>>();
18173        self.fold_creases(ranges, true, window, cx);
18174    }
18175
18176    pub fn fold_ranges<T: ToOffset + Clone>(
18177        &mut self,
18178        ranges: Vec<Range<T>>,
18179        auto_scroll: bool,
18180        window: &mut Window,
18181        cx: &mut Context<Self>,
18182    ) {
18183        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18184        let ranges = ranges
18185            .into_iter()
18186            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18187            .collect::<Vec<_>>();
18188        self.fold_creases(ranges, auto_scroll, window, cx);
18189    }
18190
18191    pub fn fold_creases<T: ToOffset + Clone>(
18192        &mut self,
18193        creases: Vec<Crease<T>>,
18194        auto_scroll: bool,
18195        _window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        if creases.is_empty() {
18199            return;
18200        }
18201
18202        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18203
18204        if auto_scroll {
18205            self.request_autoscroll(Autoscroll::fit(), cx);
18206        }
18207
18208        cx.notify();
18209
18210        self.scrollbar_marker_state.dirty = true;
18211        self.folds_did_change(cx);
18212    }
18213
18214    /// Removes any folds whose ranges intersect any of the given ranges.
18215    pub fn unfold_ranges<T: ToOffset + Clone>(
18216        &mut self,
18217        ranges: &[Range<T>],
18218        inclusive: bool,
18219        auto_scroll: bool,
18220        cx: &mut Context<Self>,
18221    ) {
18222        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18223            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18224        });
18225        self.folds_did_change(cx);
18226    }
18227
18228    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18229        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18230            return;
18231        }
18232        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18233        self.display_map.update(cx, |display_map, cx| {
18234            display_map.fold_buffers([buffer_id], cx)
18235        });
18236        cx.emit(EditorEvent::BufferFoldToggled {
18237            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18238            folded: true,
18239        });
18240        cx.notify();
18241    }
18242
18243    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18244        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18245            return;
18246        }
18247        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18248        self.display_map.update(cx, |display_map, cx| {
18249            display_map.unfold_buffers([buffer_id], cx);
18250        });
18251        cx.emit(EditorEvent::BufferFoldToggled {
18252            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18253            folded: false,
18254        });
18255        cx.notify();
18256    }
18257
18258    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18259        self.display_map.read(cx).is_buffer_folded(buffer)
18260    }
18261
18262    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18263        self.display_map.read(cx).folded_buffers()
18264    }
18265
18266    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18267        self.display_map.update(cx, |display_map, cx| {
18268            display_map.disable_header_for_buffer(buffer_id, cx);
18269        });
18270        cx.notify();
18271    }
18272
18273    /// Removes any folds with the given ranges.
18274    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18275        &mut self,
18276        ranges: &[Range<T>],
18277        type_id: TypeId,
18278        auto_scroll: bool,
18279        cx: &mut Context<Self>,
18280    ) {
18281        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18282            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18283        });
18284        self.folds_did_change(cx);
18285    }
18286
18287    fn remove_folds_with<T: ToOffset + Clone>(
18288        &mut self,
18289        ranges: &[Range<T>],
18290        auto_scroll: bool,
18291        cx: &mut Context<Self>,
18292        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18293    ) {
18294        if ranges.is_empty() {
18295            return;
18296        }
18297
18298        let mut buffers_affected = HashSet::default();
18299        let multi_buffer = self.buffer().read(cx);
18300        for range in ranges {
18301            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18302                buffers_affected.insert(buffer.read(cx).remote_id());
18303            };
18304        }
18305
18306        self.display_map.update(cx, update);
18307
18308        if auto_scroll {
18309            self.request_autoscroll(Autoscroll::fit(), cx);
18310        }
18311
18312        cx.notify();
18313        self.scrollbar_marker_state.dirty = true;
18314        self.active_indent_guides_state.dirty = true;
18315    }
18316
18317    pub fn update_renderer_widths(
18318        &mut self,
18319        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18320        cx: &mut Context<Self>,
18321    ) -> bool {
18322        self.display_map
18323            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18324    }
18325
18326    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18327        self.display_map.read(cx).fold_placeholder.clone()
18328    }
18329
18330    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18331        self.buffer.update(cx, |buffer, cx| {
18332            buffer.set_all_diff_hunks_expanded(cx);
18333        });
18334    }
18335
18336    pub fn expand_all_diff_hunks(
18337        &mut self,
18338        _: &ExpandAllDiffHunks,
18339        _window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        self.buffer.update(cx, |buffer, cx| {
18343            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18344        });
18345    }
18346
18347    pub fn toggle_selected_diff_hunks(
18348        &mut self,
18349        _: &ToggleSelectedDiffHunks,
18350        _window: &mut Window,
18351        cx: &mut Context<Self>,
18352    ) {
18353        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18354        self.toggle_diff_hunks_in_ranges(ranges, cx);
18355    }
18356
18357    pub fn diff_hunks_in_ranges<'a>(
18358        &'a self,
18359        ranges: &'a [Range<Anchor>],
18360        buffer: &'a MultiBufferSnapshot,
18361    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18362        ranges.iter().flat_map(move |range| {
18363            let end_excerpt_id = range.end.excerpt_id;
18364            let range = range.to_point(buffer);
18365            let mut peek_end = range.end;
18366            if range.end.row < buffer.max_row().0 {
18367                peek_end = Point::new(range.end.row + 1, 0);
18368            }
18369            buffer
18370                .diff_hunks_in_range(range.start..peek_end)
18371                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18372        })
18373    }
18374
18375    pub fn has_stageable_diff_hunks_in_ranges(
18376        &self,
18377        ranges: &[Range<Anchor>],
18378        snapshot: &MultiBufferSnapshot,
18379    ) -> bool {
18380        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18381        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18382    }
18383
18384    pub fn toggle_staged_selected_diff_hunks(
18385        &mut self,
18386        _: &::git::ToggleStaged,
18387        _: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        let snapshot = self.buffer.read(cx).snapshot(cx);
18391        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18392        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18393        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18394    }
18395
18396    pub fn set_render_diff_hunk_controls(
18397        &mut self,
18398        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18399        cx: &mut Context<Self>,
18400    ) {
18401        self.render_diff_hunk_controls = render_diff_hunk_controls;
18402        cx.notify();
18403    }
18404
18405    pub fn stage_and_next(
18406        &mut self,
18407        _: &::git::StageAndNext,
18408        window: &mut Window,
18409        cx: &mut Context<Self>,
18410    ) {
18411        self.do_stage_or_unstage_and_next(true, window, cx);
18412    }
18413
18414    pub fn unstage_and_next(
18415        &mut self,
18416        _: &::git::UnstageAndNext,
18417        window: &mut Window,
18418        cx: &mut Context<Self>,
18419    ) {
18420        self.do_stage_or_unstage_and_next(false, window, cx);
18421    }
18422
18423    pub fn stage_or_unstage_diff_hunks(
18424        &mut self,
18425        stage: bool,
18426        ranges: Vec<Range<Anchor>>,
18427        cx: &mut Context<Self>,
18428    ) {
18429        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18430        cx.spawn(async move |this, cx| {
18431            task.await?;
18432            this.update(cx, |this, cx| {
18433                let snapshot = this.buffer.read(cx).snapshot(cx);
18434                let chunk_by = this
18435                    .diff_hunks_in_ranges(&ranges, &snapshot)
18436                    .chunk_by(|hunk| hunk.buffer_id);
18437                for (buffer_id, hunks) in &chunk_by {
18438                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18439                }
18440            })
18441        })
18442        .detach_and_log_err(cx);
18443    }
18444
18445    fn save_buffers_for_ranges_if_needed(
18446        &mut self,
18447        ranges: &[Range<Anchor>],
18448        cx: &mut Context<Editor>,
18449    ) -> Task<Result<()>> {
18450        let multibuffer = self.buffer.read(cx);
18451        let snapshot = multibuffer.read(cx);
18452        let buffer_ids: HashSet<_> = ranges
18453            .iter()
18454            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18455            .collect();
18456        drop(snapshot);
18457
18458        let mut buffers = HashSet::default();
18459        for buffer_id in buffer_ids {
18460            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18461                let buffer = buffer_entity.read(cx);
18462                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18463                {
18464                    buffers.insert(buffer_entity);
18465                }
18466            }
18467        }
18468
18469        if let Some(project) = &self.project {
18470            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18471        } else {
18472            Task::ready(Ok(()))
18473        }
18474    }
18475
18476    fn do_stage_or_unstage_and_next(
18477        &mut self,
18478        stage: bool,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18483
18484        if ranges.iter().any(|range| range.start != range.end) {
18485            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18486            return;
18487        }
18488
18489        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18490        let snapshot = self.snapshot(window, cx);
18491        let position = self.selections.newest::<Point>(cx).head();
18492        let mut row = snapshot
18493            .buffer_snapshot
18494            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18495            .find(|hunk| hunk.row_range.start.0 > position.row)
18496            .map(|hunk| hunk.row_range.start);
18497
18498        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18499        // Outside of the project diff editor, wrap around to the beginning.
18500        if !all_diff_hunks_expanded {
18501            row = row.or_else(|| {
18502                snapshot
18503                    .buffer_snapshot
18504                    .diff_hunks_in_range(Point::zero()..position)
18505                    .find(|hunk| hunk.row_range.end.0 < position.row)
18506                    .map(|hunk| hunk.row_range.start)
18507            });
18508        }
18509
18510        if let Some(row) = row {
18511            let destination = Point::new(row.0, 0);
18512            let autoscroll = Autoscroll::center();
18513
18514            self.unfold_ranges(&[destination..destination], false, false, cx);
18515            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18516                s.select_ranges([destination..destination]);
18517            });
18518        }
18519    }
18520
18521    fn do_stage_or_unstage(
18522        &self,
18523        stage: bool,
18524        buffer_id: BufferId,
18525        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18526        cx: &mut App,
18527    ) -> Option<()> {
18528        let project = self.project()?;
18529        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18530        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18531        let buffer_snapshot = buffer.read(cx).snapshot();
18532        let file_exists = buffer_snapshot
18533            .file()
18534            .is_some_and(|file| file.disk_state().exists());
18535        diff.update(cx, |diff, cx| {
18536            diff.stage_or_unstage_hunks(
18537                stage,
18538                &hunks
18539                    .map(|hunk| buffer_diff::DiffHunk {
18540                        buffer_range: hunk.buffer_range,
18541                        diff_base_byte_range: hunk.diff_base_byte_range,
18542                        secondary_status: hunk.secondary_status,
18543                        range: Point::zero()..Point::zero(), // unused
18544                    })
18545                    .collect::<Vec<_>>(),
18546                &buffer_snapshot,
18547                file_exists,
18548                cx,
18549            )
18550        });
18551        None
18552    }
18553
18554    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18555        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18556        self.buffer
18557            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18558    }
18559
18560    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18561        self.buffer.update(cx, |buffer, cx| {
18562            let ranges = vec![Anchor::min()..Anchor::max()];
18563            if !buffer.all_diff_hunks_expanded()
18564                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18565            {
18566                buffer.collapse_diff_hunks(ranges, cx);
18567                true
18568            } else {
18569                false
18570            }
18571        })
18572    }
18573
18574    fn toggle_diff_hunks_in_ranges(
18575        &mut self,
18576        ranges: Vec<Range<Anchor>>,
18577        cx: &mut Context<Editor>,
18578    ) {
18579        self.buffer.update(cx, |buffer, cx| {
18580            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18581            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18582        })
18583    }
18584
18585    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18586        self.buffer.update(cx, |buffer, cx| {
18587            let snapshot = buffer.snapshot(cx);
18588            let excerpt_id = range.end.excerpt_id;
18589            let point_range = range.to_point(&snapshot);
18590            let expand = !buffer.single_hunk_is_expanded(range, cx);
18591            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18592        })
18593    }
18594
18595    pub(crate) fn apply_all_diff_hunks(
18596        &mut self,
18597        _: &ApplyAllDiffHunks,
18598        window: &mut Window,
18599        cx: &mut Context<Self>,
18600    ) {
18601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18602
18603        let buffers = self.buffer.read(cx).all_buffers();
18604        for branch_buffer in buffers {
18605            branch_buffer.update(cx, |branch_buffer, cx| {
18606                branch_buffer.merge_into_base(Vec::new(), cx);
18607            });
18608        }
18609
18610        if let Some(project) = self.project.clone() {
18611            self.save(
18612                SaveOptions {
18613                    format: true,
18614                    autosave: false,
18615                },
18616                project,
18617                window,
18618                cx,
18619            )
18620            .detach_and_log_err(cx);
18621        }
18622    }
18623
18624    pub(crate) fn apply_selected_diff_hunks(
18625        &mut self,
18626        _: &ApplyDiffHunk,
18627        window: &mut Window,
18628        cx: &mut Context<Self>,
18629    ) {
18630        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18631        let snapshot = self.snapshot(window, cx);
18632        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18633        let mut ranges_by_buffer = HashMap::default();
18634        self.transact(window, cx, |editor, _window, cx| {
18635            for hunk in hunks {
18636                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18637                    ranges_by_buffer
18638                        .entry(buffer.clone())
18639                        .or_insert_with(Vec::new)
18640                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18641                }
18642            }
18643
18644            for (buffer, ranges) in ranges_by_buffer {
18645                buffer.update(cx, |buffer, cx| {
18646                    buffer.merge_into_base(ranges, cx);
18647                });
18648            }
18649        });
18650
18651        if let Some(project) = self.project.clone() {
18652            self.save(
18653                SaveOptions {
18654                    format: true,
18655                    autosave: false,
18656                },
18657                project,
18658                window,
18659                cx,
18660            )
18661            .detach_and_log_err(cx);
18662        }
18663    }
18664
18665    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18666        if hovered != self.gutter_hovered {
18667            self.gutter_hovered = hovered;
18668            cx.notify();
18669        }
18670    }
18671
18672    pub fn insert_blocks(
18673        &mut self,
18674        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18675        autoscroll: Option<Autoscroll>,
18676        cx: &mut Context<Self>,
18677    ) -> Vec<CustomBlockId> {
18678        let blocks = self
18679            .display_map
18680            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18681        if let Some(autoscroll) = autoscroll {
18682            self.request_autoscroll(autoscroll, cx);
18683        }
18684        cx.notify();
18685        blocks
18686    }
18687
18688    pub fn resize_blocks(
18689        &mut self,
18690        heights: HashMap<CustomBlockId, u32>,
18691        autoscroll: Option<Autoscroll>,
18692        cx: &mut Context<Self>,
18693    ) {
18694        self.display_map
18695            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18696        if let Some(autoscroll) = autoscroll {
18697            self.request_autoscroll(autoscroll, cx);
18698        }
18699        cx.notify();
18700    }
18701
18702    pub fn replace_blocks(
18703        &mut self,
18704        renderers: HashMap<CustomBlockId, RenderBlock>,
18705        autoscroll: Option<Autoscroll>,
18706        cx: &mut Context<Self>,
18707    ) {
18708        self.display_map
18709            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18710        if let Some(autoscroll) = autoscroll {
18711            self.request_autoscroll(autoscroll, cx);
18712        }
18713        cx.notify();
18714    }
18715
18716    pub fn remove_blocks(
18717        &mut self,
18718        block_ids: HashSet<CustomBlockId>,
18719        autoscroll: Option<Autoscroll>,
18720        cx: &mut Context<Self>,
18721    ) {
18722        self.display_map.update(cx, |display_map, cx| {
18723            display_map.remove_blocks(block_ids, cx)
18724        });
18725        if let Some(autoscroll) = autoscroll {
18726            self.request_autoscroll(autoscroll, cx);
18727        }
18728        cx.notify();
18729    }
18730
18731    pub fn row_for_block(
18732        &self,
18733        block_id: CustomBlockId,
18734        cx: &mut Context<Self>,
18735    ) -> Option<DisplayRow> {
18736        self.display_map
18737            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18738    }
18739
18740    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18741        self.focused_block = Some(focused_block);
18742    }
18743
18744    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18745        self.focused_block.take()
18746    }
18747
18748    pub fn insert_creases(
18749        &mut self,
18750        creases: impl IntoIterator<Item = Crease<Anchor>>,
18751        cx: &mut Context<Self>,
18752    ) -> Vec<CreaseId> {
18753        self.display_map
18754            .update(cx, |map, cx| map.insert_creases(creases, cx))
18755    }
18756
18757    pub fn remove_creases(
18758        &mut self,
18759        ids: impl IntoIterator<Item = CreaseId>,
18760        cx: &mut Context<Self>,
18761    ) -> Vec<(CreaseId, Range<Anchor>)> {
18762        self.display_map
18763            .update(cx, |map, cx| map.remove_creases(ids, cx))
18764    }
18765
18766    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18767        self.display_map
18768            .update(cx, |map, cx| map.snapshot(cx))
18769            .longest_row()
18770    }
18771
18772    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18773        self.display_map
18774            .update(cx, |map, cx| map.snapshot(cx))
18775            .max_point()
18776    }
18777
18778    pub fn text(&self, cx: &App) -> String {
18779        self.buffer.read(cx).read(cx).text()
18780    }
18781
18782    pub fn is_empty(&self, cx: &App) -> bool {
18783        self.buffer.read(cx).read(cx).is_empty()
18784    }
18785
18786    pub fn text_option(&self, cx: &App) -> Option<String> {
18787        let text = self.text(cx);
18788        let text = text.trim();
18789
18790        if text.is_empty() {
18791            return None;
18792        }
18793
18794        Some(text.to_string())
18795    }
18796
18797    pub fn set_text(
18798        &mut self,
18799        text: impl Into<Arc<str>>,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.transact(window, cx, |this, _, cx| {
18804            this.buffer
18805                .read(cx)
18806                .as_singleton()
18807                .expect("you can only call set_text on editors for singleton buffers")
18808                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18809        });
18810    }
18811
18812    pub fn display_text(&self, cx: &mut App) -> String {
18813        self.display_map
18814            .update(cx, |map, cx| map.snapshot(cx))
18815            .text()
18816    }
18817
18818    fn create_minimap(
18819        &self,
18820        minimap_settings: MinimapSettings,
18821        window: &mut Window,
18822        cx: &mut Context<Self>,
18823    ) -> Option<Entity<Self>> {
18824        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18825            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18826    }
18827
18828    fn initialize_new_minimap(
18829        &self,
18830        minimap_settings: MinimapSettings,
18831        window: &mut Window,
18832        cx: &mut Context<Self>,
18833    ) -> Entity<Self> {
18834        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18835
18836        let mut minimap = Editor::new_internal(
18837            EditorMode::Minimap {
18838                parent: cx.weak_entity(),
18839            },
18840            self.buffer.clone(),
18841            None,
18842            Some(self.display_map.clone()),
18843            window,
18844            cx,
18845        );
18846        minimap.scroll_manager.clone_state(&self.scroll_manager);
18847        minimap.set_text_style_refinement(TextStyleRefinement {
18848            font_size: Some(MINIMAP_FONT_SIZE),
18849            font_weight: Some(MINIMAP_FONT_WEIGHT),
18850            ..Default::default()
18851        });
18852        minimap.update_minimap_configuration(minimap_settings, cx);
18853        cx.new(|_| minimap)
18854    }
18855
18856    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18857        let current_line_highlight = minimap_settings
18858            .current_line_highlight
18859            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18860        self.set_current_line_highlight(Some(current_line_highlight));
18861    }
18862
18863    pub fn minimap(&self) -> Option<&Entity<Self>> {
18864        self.minimap
18865            .as_ref()
18866            .filter(|_| self.minimap_visibility.visible())
18867    }
18868
18869    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18870        let mut wrap_guides = smallvec![];
18871
18872        if self.show_wrap_guides == Some(false) {
18873            return wrap_guides;
18874        }
18875
18876        let settings = self.buffer.read(cx).language_settings(cx);
18877        if settings.show_wrap_guides {
18878            match self.soft_wrap_mode(cx) {
18879                SoftWrap::Column(soft_wrap) => {
18880                    wrap_guides.push((soft_wrap as usize, true));
18881                }
18882                SoftWrap::Bounded(soft_wrap) => {
18883                    wrap_guides.push((soft_wrap as usize, true));
18884                }
18885                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18886            }
18887            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18888        }
18889
18890        wrap_guides
18891    }
18892
18893    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18894        let settings = self.buffer.read(cx).language_settings(cx);
18895        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18896        match mode {
18897            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18898                SoftWrap::None
18899            }
18900            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18901            language_settings::SoftWrap::PreferredLineLength => {
18902                SoftWrap::Column(settings.preferred_line_length)
18903            }
18904            language_settings::SoftWrap::Bounded => {
18905                SoftWrap::Bounded(settings.preferred_line_length)
18906            }
18907        }
18908    }
18909
18910    pub fn set_soft_wrap_mode(
18911        &mut self,
18912        mode: language_settings::SoftWrap,
18913
18914        cx: &mut Context<Self>,
18915    ) {
18916        self.soft_wrap_mode_override = Some(mode);
18917        cx.notify();
18918    }
18919
18920    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18921        self.hard_wrap = hard_wrap;
18922        cx.notify();
18923    }
18924
18925    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18926        self.text_style_refinement = Some(style);
18927    }
18928
18929    /// called by the Element so we know what style we were most recently rendered with.
18930    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
18931        // We intentionally do not inform the display map about the minimap style
18932        // so that wrapping is not recalculated and stays consistent for the editor
18933        // and its linked minimap.
18934        if !self.mode.is_minimap() {
18935            let font = style.text.font();
18936            let font_size = style.text.font_size.to_pixels(window.rem_size());
18937            let display_map = self
18938                .placeholder_display_map
18939                .as_ref()
18940                .filter(|_| self.is_empty(cx))
18941                .unwrap_or(&self.display_map);
18942
18943            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
18944        }
18945        self.style = Some(style);
18946    }
18947
18948    pub fn style(&self) -> Option<&EditorStyle> {
18949        self.style.as_ref()
18950    }
18951
18952    // Called by the element. This method is not designed to be called outside of the editor
18953    // element's layout code because it does not notify when rewrapping is computed synchronously.
18954    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18955        if self.is_empty(cx) {
18956            self.placeholder_display_map
18957                .as_ref()
18958                .map_or(false, |display_map| {
18959                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
18960                })
18961        } else {
18962            self.display_map
18963                .update(cx, |map, cx| map.set_wrap_width(width, cx))
18964        }
18965    }
18966
18967    pub fn set_soft_wrap(&mut self) {
18968        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18969    }
18970
18971    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18972        if self.soft_wrap_mode_override.is_some() {
18973            self.soft_wrap_mode_override.take();
18974        } else {
18975            let soft_wrap = match self.soft_wrap_mode(cx) {
18976                SoftWrap::GitDiff => return,
18977                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18978                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18979                    language_settings::SoftWrap::None
18980                }
18981            };
18982            self.soft_wrap_mode_override = Some(soft_wrap);
18983        }
18984        cx.notify();
18985    }
18986
18987    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18988        let Some(workspace) = self.workspace() else {
18989            return;
18990        };
18991        let fs = workspace.read(cx).app_state().fs.clone();
18992        let current_show = TabBarSettings::get_global(cx).show;
18993        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18994            setting.show = Some(!current_show);
18995        });
18996    }
18997
18998    pub fn toggle_indent_guides(
18999        &mut self,
19000        _: &ToggleIndentGuides,
19001        _: &mut Window,
19002        cx: &mut Context<Self>,
19003    ) {
19004        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19005            self.buffer
19006                .read(cx)
19007                .language_settings(cx)
19008                .indent_guides
19009                .enabled
19010        });
19011        self.show_indent_guides = Some(!currently_enabled);
19012        cx.notify();
19013    }
19014
19015    fn should_show_indent_guides(&self) -> Option<bool> {
19016        self.show_indent_guides
19017    }
19018
19019    pub fn toggle_line_numbers(
19020        &mut self,
19021        _: &ToggleLineNumbers,
19022        _: &mut Window,
19023        cx: &mut Context<Self>,
19024    ) {
19025        let mut editor_settings = EditorSettings::get_global(cx).clone();
19026        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19027        EditorSettings::override_global(editor_settings, cx);
19028    }
19029
19030    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19031        if let Some(show_line_numbers) = self.show_line_numbers {
19032            return show_line_numbers;
19033        }
19034        EditorSettings::get_global(cx).gutter.line_numbers
19035    }
19036
19037    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19038        self.use_relative_line_numbers
19039            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19040    }
19041
19042    pub fn toggle_relative_line_numbers(
19043        &mut self,
19044        _: &ToggleRelativeLineNumbers,
19045        _: &mut Window,
19046        cx: &mut Context<Self>,
19047    ) {
19048        let is_relative = self.should_use_relative_line_numbers(cx);
19049        self.set_relative_line_number(Some(!is_relative), cx)
19050    }
19051
19052    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19053        self.use_relative_line_numbers = is_relative;
19054        cx.notify();
19055    }
19056
19057    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19058        self.show_gutter = show_gutter;
19059        cx.notify();
19060    }
19061
19062    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19063        self.show_scrollbars = ScrollbarAxes {
19064            horizontal: show,
19065            vertical: show,
19066        };
19067        cx.notify();
19068    }
19069
19070    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19071        self.show_scrollbars.vertical = show;
19072        cx.notify();
19073    }
19074
19075    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19076        self.show_scrollbars.horizontal = show;
19077        cx.notify();
19078    }
19079
19080    pub fn set_minimap_visibility(
19081        &mut self,
19082        minimap_visibility: MinimapVisibility,
19083        window: &mut Window,
19084        cx: &mut Context<Self>,
19085    ) {
19086        if self.minimap_visibility != minimap_visibility {
19087            if minimap_visibility.visible() && self.minimap.is_none() {
19088                let minimap_settings = EditorSettings::get_global(cx).minimap;
19089                self.minimap =
19090                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19091            }
19092            self.minimap_visibility = minimap_visibility;
19093            cx.notify();
19094        }
19095    }
19096
19097    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19098        self.set_show_scrollbars(false, cx);
19099        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19100    }
19101
19102    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19103        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19104    }
19105
19106    /// Normally the text in full mode and auto height editors is padded on the
19107    /// left side by roughly half a character width for improved hit testing.
19108    ///
19109    /// Use this method to disable this for cases where this is not wanted (e.g.
19110    /// if you want to align the editor text with some other text above or below)
19111    /// or if you want to add this padding to single-line editors.
19112    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19113        self.offset_content = offset_content;
19114        cx.notify();
19115    }
19116
19117    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19118        self.show_line_numbers = Some(show_line_numbers);
19119        cx.notify();
19120    }
19121
19122    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19123        self.disable_expand_excerpt_buttons = true;
19124        cx.notify();
19125    }
19126
19127    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19128        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19129        cx.notify();
19130    }
19131
19132    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19133        self.show_code_actions = Some(show_code_actions);
19134        cx.notify();
19135    }
19136
19137    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19138        self.show_runnables = Some(show_runnables);
19139        cx.notify();
19140    }
19141
19142    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19143        self.show_breakpoints = Some(show_breakpoints);
19144        cx.notify();
19145    }
19146
19147    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19148        if self.display_map.read(cx).masked != masked {
19149            self.display_map.update(cx, |map, _| map.masked = masked);
19150        }
19151        cx.notify()
19152    }
19153
19154    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19155        self.show_wrap_guides = Some(show_wrap_guides);
19156        cx.notify();
19157    }
19158
19159    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19160        self.show_indent_guides = Some(show_indent_guides);
19161        cx.notify();
19162    }
19163
19164    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19165        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19166            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19167                && let Some(dir) = file.abs_path(cx).parent()
19168            {
19169                return Some(dir.to_owned());
19170            }
19171
19172            if let Some(project_path) = buffer.read(cx).project_path(cx) {
19173                return Some(project_path.path.to_path_buf());
19174            }
19175        }
19176
19177        None
19178    }
19179
19180    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19181        self.active_excerpt(cx)?
19182            .1
19183            .read(cx)
19184            .file()
19185            .and_then(|f| f.as_local())
19186    }
19187
19188    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19189        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19190            let buffer = buffer.read(cx);
19191            if let Some(project_path) = buffer.project_path(cx) {
19192                let project = self.project()?.read(cx);
19193                project.absolute_path(&project_path, cx)
19194            } else {
19195                buffer
19196                    .file()
19197                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19198            }
19199        })
19200    }
19201
19202    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19203        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19204            let project_path = buffer.read(cx).project_path(cx)?;
19205            let project = self.project()?.read(cx);
19206            let entry = project.entry_for_path(&project_path, cx)?;
19207            let path = entry.path.to_path_buf();
19208            Some(path)
19209        })
19210    }
19211
19212    pub fn reveal_in_finder(
19213        &mut self,
19214        _: &RevealInFileManager,
19215        _window: &mut Window,
19216        cx: &mut Context<Self>,
19217    ) {
19218        if let Some(target) = self.target_file(cx) {
19219            cx.reveal_path(&target.abs_path(cx));
19220        }
19221    }
19222
19223    pub fn copy_path(
19224        &mut self,
19225        _: &zed_actions::workspace::CopyPath,
19226        _window: &mut Window,
19227        cx: &mut Context<Self>,
19228    ) {
19229        if let Some(path) = self.target_file_abs_path(cx)
19230            && let Some(path) = path.to_str()
19231        {
19232            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19233        }
19234    }
19235
19236    pub fn copy_relative_path(
19237        &mut self,
19238        _: &zed_actions::workspace::CopyRelativePath,
19239        _window: &mut Window,
19240        cx: &mut Context<Self>,
19241    ) {
19242        if let Some(path) = self.target_file_path(cx)
19243            && let Some(path) = path.to_str()
19244        {
19245            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19246        }
19247    }
19248
19249    /// Returns the project path for the editor's buffer, if any buffer is
19250    /// opened in the editor.
19251    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19252        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19253            buffer.read(cx).project_path(cx)
19254        } else {
19255            None
19256        }
19257    }
19258
19259    // Returns true if the editor handled a go-to-line request
19260    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19261        maybe!({
19262            let breakpoint_store = self.breakpoint_store.as_ref()?;
19263
19264            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19265            else {
19266                self.clear_row_highlights::<ActiveDebugLine>();
19267                return None;
19268            };
19269
19270            let position = active_stack_frame.position;
19271            let buffer_id = position.buffer_id?;
19272            let snapshot = self
19273                .project
19274                .as_ref()?
19275                .read(cx)
19276                .buffer_for_id(buffer_id, cx)?
19277                .read(cx)
19278                .snapshot();
19279
19280            let mut handled = false;
19281            for (id, ExcerptRange { context, .. }) in
19282                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19283            {
19284                if context.start.cmp(&position, &snapshot).is_ge()
19285                    || context.end.cmp(&position, &snapshot).is_lt()
19286                {
19287                    continue;
19288                }
19289                let snapshot = self.buffer.read(cx).snapshot(cx);
19290                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19291
19292                handled = true;
19293                self.clear_row_highlights::<ActiveDebugLine>();
19294
19295                self.go_to_line::<ActiveDebugLine>(
19296                    multibuffer_anchor,
19297                    Some(cx.theme().colors().editor_debugger_active_line_background),
19298                    window,
19299                    cx,
19300                );
19301
19302                cx.notify();
19303            }
19304
19305            handled.then_some(())
19306        })
19307        .is_some()
19308    }
19309
19310    pub fn copy_file_name_without_extension(
19311        &mut self,
19312        _: &CopyFileNameWithoutExtension,
19313        _: &mut Window,
19314        cx: &mut Context<Self>,
19315    ) {
19316        if let Some(file) = self.target_file(cx)
19317            && let Some(file_stem) = file.path().file_stem()
19318            && let Some(name) = file_stem.to_str()
19319        {
19320            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19321        }
19322    }
19323
19324    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19325        if let Some(file) = self.target_file(cx)
19326            && let Some(file_name) = file.path().file_name()
19327            && let Some(name) = file_name.to_str()
19328        {
19329            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19330        }
19331    }
19332
19333    pub fn toggle_git_blame(
19334        &mut self,
19335        _: &::git::Blame,
19336        window: &mut Window,
19337        cx: &mut Context<Self>,
19338    ) {
19339        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19340
19341        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19342            self.start_git_blame(true, window, cx);
19343        }
19344
19345        cx.notify();
19346    }
19347
19348    pub fn toggle_git_blame_inline(
19349        &mut self,
19350        _: &ToggleGitBlameInline,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) {
19354        self.toggle_git_blame_inline_internal(true, window, cx);
19355        cx.notify();
19356    }
19357
19358    pub fn open_git_blame_commit(
19359        &mut self,
19360        _: &OpenGitBlameCommit,
19361        window: &mut Window,
19362        cx: &mut Context<Self>,
19363    ) {
19364        self.open_git_blame_commit_internal(window, cx);
19365    }
19366
19367    fn open_git_blame_commit_internal(
19368        &mut self,
19369        window: &mut Window,
19370        cx: &mut Context<Self>,
19371    ) -> Option<()> {
19372        let blame = self.blame.as_ref()?;
19373        let snapshot = self.snapshot(window, cx);
19374        let cursor = self.selections.newest::<Point>(cx).head();
19375        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
19376        let (_, blame_entry) = blame
19377            .update(cx, |blame, cx| {
19378                blame
19379                    .blame_for_rows(
19380                        &[RowInfo {
19381                            buffer_id: Some(buffer.remote_id()),
19382                            buffer_row: Some(point.row),
19383                            ..Default::default()
19384                        }],
19385                        cx,
19386                    )
19387                    .next()
19388            })
19389            .flatten()?;
19390        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19391        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19392        let workspace = self.workspace()?.downgrade();
19393        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19394        None
19395    }
19396
19397    pub fn git_blame_inline_enabled(&self) -> bool {
19398        self.git_blame_inline_enabled
19399    }
19400
19401    pub fn toggle_selection_menu(
19402        &mut self,
19403        _: &ToggleSelectionMenu,
19404        _: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        self.show_selection_menu = self
19408            .show_selection_menu
19409            .map(|show_selections_menu| !show_selections_menu)
19410            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19411
19412        cx.notify();
19413    }
19414
19415    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19416        self.show_selection_menu
19417            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19418    }
19419
19420    fn start_git_blame(
19421        &mut self,
19422        user_triggered: bool,
19423        window: &mut Window,
19424        cx: &mut Context<Self>,
19425    ) {
19426        if let Some(project) = self.project() {
19427            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19428                && buffer.read(cx).file().is_none()
19429            {
19430                return;
19431            }
19432
19433            let focused = self.focus_handle(cx).contains_focused(window, cx);
19434
19435            let project = project.clone();
19436            let blame = cx
19437                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19438            self.blame_subscription =
19439                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19440            self.blame = Some(blame);
19441        }
19442    }
19443
19444    fn toggle_git_blame_inline_internal(
19445        &mut self,
19446        user_triggered: bool,
19447        window: &mut Window,
19448        cx: &mut Context<Self>,
19449    ) {
19450        if self.git_blame_inline_enabled {
19451            self.git_blame_inline_enabled = false;
19452            self.show_git_blame_inline = false;
19453            self.show_git_blame_inline_delay_task.take();
19454        } else {
19455            self.git_blame_inline_enabled = true;
19456            self.start_git_blame_inline(user_triggered, window, cx);
19457        }
19458
19459        cx.notify();
19460    }
19461
19462    fn start_git_blame_inline(
19463        &mut self,
19464        user_triggered: bool,
19465        window: &mut Window,
19466        cx: &mut Context<Self>,
19467    ) {
19468        self.start_git_blame(user_triggered, window, cx);
19469
19470        if ProjectSettings::get_global(cx)
19471            .git
19472            .inline_blame_delay()
19473            .is_some()
19474        {
19475            self.start_inline_blame_timer(window, cx);
19476        } else {
19477            self.show_git_blame_inline = true
19478        }
19479    }
19480
19481    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19482        self.blame.as_ref()
19483    }
19484
19485    pub fn show_git_blame_gutter(&self) -> bool {
19486        self.show_git_blame_gutter
19487    }
19488
19489    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19490        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19491    }
19492
19493    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19494        self.show_git_blame_inline
19495            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19496            && !self.newest_selection_head_on_empty_line(cx)
19497            && self.has_blame_entries(cx)
19498    }
19499
19500    fn has_blame_entries(&self, cx: &App) -> bool {
19501        self.blame()
19502            .is_some_and(|blame| blame.read(cx).has_generated_entries())
19503    }
19504
19505    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19506        let cursor_anchor = self.selections.newest_anchor().head();
19507
19508        let snapshot = self.buffer.read(cx).snapshot(cx);
19509        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19510
19511        snapshot.line_len(buffer_row) == 0
19512    }
19513
19514    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19515        let buffer_and_selection = maybe!({
19516            let selection = self.selections.newest::<Point>(cx);
19517            let selection_range = selection.range();
19518
19519            let multi_buffer = self.buffer().read(cx);
19520            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19521            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19522
19523            let (buffer, range, _) = if selection.reversed {
19524                buffer_ranges.first()
19525            } else {
19526                buffer_ranges.last()
19527            }?;
19528
19529            let selection = text::ToPoint::to_point(&range.start, buffer).row
19530                ..text::ToPoint::to_point(&range.end, buffer).row;
19531            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
19532        });
19533
19534        let Some((buffer, selection)) = buffer_and_selection else {
19535            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19536        };
19537
19538        let Some(project) = self.project() else {
19539            return Task::ready(Err(anyhow!("editor does not have project")));
19540        };
19541
19542        project.update(cx, |project, cx| {
19543            project.get_permalink_to_line(&buffer, selection, cx)
19544        })
19545    }
19546
19547    pub fn copy_permalink_to_line(
19548        &mut self,
19549        _: &CopyPermalinkToLine,
19550        window: &mut Window,
19551        cx: &mut Context<Self>,
19552    ) {
19553        let permalink_task = self.get_permalink_to_line(cx);
19554        let workspace = self.workspace();
19555
19556        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19557            Ok(permalink) => {
19558                cx.update(|_, cx| {
19559                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19560                })
19561                .ok();
19562            }
19563            Err(err) => {
19564                let message = format!("Failed to copy permalink: {err}");
19565
19566                anyhow::Result::<()>::Err(err).log_err();
19567
19568                if let Some(workspace) = workspace {
19569                    workspace
19570                        .update_in(cx, |workspace, _, cx| {
19571                            struct CopyPermalinkToLine;
19572
19573                            workspace.show_toast(
19574                                Toast::new(
19575                                    NotificationId::unique::<CopyPermalinkToLine>(),
19576                                    message,
19577                                ),
19578                                cx,
19579                            )
19580                        })
19581                        .ok();
19582                }
19583            }
19584        })
19585        .detach();
19586    }
19587
19588    pub fn copy_file_location(
19589        &mut self,
19590        _: &CopyFileLocation,
19591        _: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19595        if let Some(file) = self.target_file(cx)
19596            && let Some(path) = file.path().to_str()
19597        {
19598            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19599        }
19600    }
19601
19602    pub fn open_permalink_to_line(
19603        &mut self,
19604        _: &OpenPermalinkToLine,
19605        window: &mut Window,
19606        cx: &mut Context<Self>,
19607    ) {
19608        let permalink_task = self.get_permalink_to_line(cx);
19609        let workspace = self.workspace();
19610
19611        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19612            Ok(permalink) => {
19613                cx.update(|_, cx| {
19614                    cx.open_url(permalink.as_ref());
19615                })
19616                .ok();
19617            }
19618            Err(err) => {
19619                let message = format!("Failed to open permalink: {err}");
19620
19621                anyhow::Result::<()>::Err(err).log_err();
19622
19623                if let Some(workspace) = workspace {
19624                    workspace
19625                        .update(cx, |workspace, cx| {
19626                            struct OpenPermalinkToLine;
19627
19628                            workspace.show_toast(
19629                                Toast::new(
19630                                    NotificationId::unique::<OpenPermalinkToLine>(),
19631                                    message,
19632                                ),
19633                                cx,
19634                            )
19635                        })
19636                        .ok();
19637                }
19638            }
19639        })
19640        .detach();
19641    }
19642
19643    pub fn insert_uuid_v4(
19644        &mut self,
19645        _: &InsertUuidV4,
19646        window: &mut Window,
19647        cx: &mut Context<Self>,
19648    ) {
19649        self.insert_uuid(UuidVersion::V4, window, cx);
19650    }
19651
19652    pub fn insert_uuid_v7(
19653        &mut self,
19654        _: &InsertUuidV7,
19655        window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        self.insert_uuid(UuidVersion::V7, window, cx);
19659    }
19660
19661    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19662        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19663        self.transact(window, cx, |this, window, cx| {
19664            let edits = this
19665                .selections
19666                .all::<Point>(cx)
19667                .into_iter()
19668                .map(|selection| {
19669                    let uuid = match version {
19670                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19671                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19672                    };
19673
19674                    (selection.range(), uuid.to_string())
19675                });
19676            this.edit(edits, cx);
19677            this.refresh_edit_prediction(true, false, window, cx);
19678        });
19679    }
19680
19681    pub fn open_selections_in_multibuffer(
19682        &mut self,
19683        _: &OpenSelectionsInMultibuffer,
19684        window: &mut Window,
19685        cx: &mut Context<Self>,
19686    ) {
19687        let multibuffer = self.buffer.read(cx);
19688
19689        let Some(buffer) = multibuffer.as_singleton() else {
19690            return;
19691        };
19692
19693        let Some(workspace) = self.workspace() else {
19694            return;
19695        };
19696
19697        let title = multibuffer.title(cx).to_string();
19698
19699        let locations = self
19700            .selections
19701            .all_anchors(cx)
19702            .iter()
19703            .map(|selection| Location {
19704                buffer: buffer.clone(),
19705                range: selection.start.text_anchor..selection.end.text_anchor,
19706            })
19707            .collect::<Vec<_>>();
19708
19709        cx.spawn_in(window, async move |_, cx| {
19710            workspace.update_in(cx, |workspace, window, cx| {
19711                Self::open_locations_in_multibuffer(
19712                    workspace,
19713                    locations,
19714                    format!("Selections for '{title}'"),
19715                    false,
19716                    MultibufferSelectionMode::All,
19717                    window,
19718                    cx,
19719                );
19720            })
19721        })
19722        .detach();
19723    }
19724
19725    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19726    /// last highlight added will be used.
19727    ///
19728    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19729    pub fn highlight_rows<T: 'static>(
19730        &mut self,
19731        range: Range<Anchor>,
19732        color: Hsla,
19733        options: RowHighlightOptions,
19734        cx: &mut Context<Self>,
19735    ) {
19736        let snapshot = self.buffer().read(cx).snapshot(cx);
19737        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19738        let ix = row_highlights.binary_search_by(|highlight| {
19739            Ordering::Equal
19740                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19741                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19742        });
19743
19744        if let Err(mut ix) = ix {
19745            let index = post_inc(&mut self.highlight_order);
19746
19747            // If this range intersects with the preceding highlight, then merge it with
19748            // the preceding highlight. Otherwise insert a new highlight.
19749            let mut merged = false;
19750            if ix > 0 {
19751                let prev_highlight = &mut row_highlights[ix - 1];
19752                if prev_highlight
19753                    .range
19754                    .end
19755                    .cmp(&range.start, &snapshot)
19756                    .is_ge()
19757                {
19758                    ix -= 1;
19759                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19760                        prev_highlight.range.end = range.end;
19761                    }
19762                    merged = true;
19763                    prev_highlight.index = index;
19764                    prev_highlight.color = color;
19765                    prev_highlight.options = options;
19766                }
19767            }
19768
19769            if !merged {
19770                row_highlights.insert(
19771                    ix,
19772                    RowHighlight {
19773                        range,
19774                        index,
19775                        color,
19776                        options,
19777                        type_id: TypeId::of::<T>(),
19778                    },
19779                );
19780            }
19781
19782            // If any of the following highlights intersect with this one, merge them.
19783            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19784                let highlight = &row_highlights[ix];
19785                if next_highlight
19786                    .range
19787                    .start
19788                    .cmp(&highlight.range.end, &snapshot)
19789                    .is_le()
19790                {
19791                    if next_highlight
19792                        .range
19793                        .end
19794                        .cmp(&highlight.range.end, &snapshot)
19795                        .is_gt()
19796                    {
19797                        row_highlights[ix].range.end = next_highlight.range.end;
19798                    }
19799                    row_highlights.remove(ix + 1);
19800                } else {
19801                    break;
19802                }
19803            }
19804        }
19805    }
19806
19807    /// Remove any highlighted row ranges of the given type that intersect the
19808    /// given ranges.
19809    pub fn remove_highlighted_rows<T: 'static>(
19810        &mut self,
19811        ranges_to_remove: Vec<Range<Anchor>>,
19812        cx: &mut Context<Self>,
19813    ) {
19814        let snapshot = self.buffer().read(cx).snapshot(cx);
19815        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19816        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19817        row_highlights.retain(|highlight| {
19818            while let Some(range_to_remove) = ranges_to_remove.peek() {
19819                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19820                    Ordering::Less | Ordering::Equal => {
19821                        ranges_to_remove.next();
19822                    }
19823                    Ordering::Greater => {
19824                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19825                            Ordering::Less | Ordering::Equal => {
19826                                return false;
19827                            }
19828                            Ordering::Greater => break,
19829                        }
19830                    }
19831                }
19832            }
19833
19834            true
19835        })
19836    }
19837
19838    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19839    pub fn clear_row_highlights<T: 'static>(&mut self) {
19840        self.highlighted_rows.remove(&TypeId::of::<T>());
19841    }
19842
19843    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19844    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19845        self.highlighted_rows
19846            .get(&TypeId::of::<T>())
19847            .map_or(&[] as &[_], |vec| vec.as_slice())
19848            .iter()
19849            .map(|highlight| (highlight.range.clone(), highlight.color))
19850    }
19851
19852    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19853    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19854    /// Allows to ignore certain kinds of highlights.
19855    pub fn highlighted_display_rows(
19856        &self,
19857        window: &mut Window,
19858        cx: &mut App,
19859    ) -> BTreeMap<DisplayRow, LineHighlight> {
19860        let snapshot = self.snapshot(window, cx);
19861        let mut used_highlight_orders = HashMap::default();
19862        self.highlighted_rows
19863            .iter()
19864            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19865            .fold(
19866                BTreeMap::<DisplayRow, LineHighlight>::new(),
19867                |mut unique_rows, highlight| {
19868                    let start = highlight.range.start.to_display_point(&snapshot);
19869                    let end = highlight.range.end.to_display_point(&snapshot);
19870                    let start_row = start.row().0;
19871                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19872                        && end.column() == 0
19873                    {
19874                        end.row().0.saturating_sub(1)
19875                    } else {
19876                        end.row().0
19877                    };
19878                    for row in start_row..=end_row {
19879                        let used_index =
19880                            used_highlight_orders.entry(row).or_insert(highlight.index);
19881                        if highlight.index >= *used_index {
19882                            *used_index = highlight.index;
19883                            unique_rows.insert(
19884                                DisplayRow(row),
19885                                LineHighlight {
19886                                    include_gutter: highlight.options.include_gutter,
19887                                    border: None,
19888                                    background: highlight.color.into(),
19889                                    type_id: Some(highlight.type_id),
19890                                },
19891                            );
19892                        }
19893                    }
19894                    unique_rows
19895                },
19896            )
19897    }
19898
19899    pub fn highlighted_display_row_for_autoscroll(
19900        &self,
19901        snapshot: &DisplaySnapshot,
19902    ) -> Option<DisplayRow> {
19903        self.highlighted_rows
19904            .values()
19905            .flat_map(|highlighted_rows| highlighted_rows.iter())
19906            .filter_map(|highlight| {
19907                if highlight.options.autoscroll {
19908                    Some(highlight.range.start.to_display_point(snapshot).row())
19909                } else {
19910                    None
19911                }
19912            })
19913            .min()
19914    }
19915
19916    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19917        self.highlight_background::<SearchWithinRange>(
19918            ranges,
19919            |colors| colors.colors().editor_document_highlight_read_background,
19920            cx,
19921        )
19922    }
19923
19924    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19925        self.breadcrumb_header = Some(new_header);
19926    }
19927
19928    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19929        self.clear_background_highlights::<SearchWithinRange>(cx);
19930    }
19931
19932    pub fn highlight_background<T: 'static>(
19933        &mut self,
19934        ranges: &[Range<Anchor>],
19935        color_fetcher: fn(&Theme) -> Hsla,
19936        cx: &mut Context<Self>,
19937    ) {
19938        self.background_highlights.insert(
19939            HighlightKey::Type(TypeId::of::<T>()),
19940            (color_fetcher, Arc::from(ranges)),
19941        );
19942        self.scrollbar_marker_state.dirty = true;
19943        cx.notify();
19944    }
19945
19946    pub fn highlight_background_key<T: 'static>(
19947        &mut self,
19948        key: usize,
19949        ranges: &[Range<Anchor>],
19950        color_fetcher: fn(&Theme) -> Hsla,
19951        cx: &mut Context<Self>,
19952    ) {
19953        self.background_highlights.insert(
19954            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19955            (color_fetcher, Arc::from(ranges)),
19956        );
19957        self.scrollbar_marker_state.dirty = true;
19958        cx.notify();
19959    }
19960
19961    pub fn clear_background_highlights<T: 'static>(
19962        &mut self,
19963        cx: &mut Context<Self>,
19964    ) -> Option<BackgroundHighlight> {
19965        let text_highlights = self
19966            .background_highlights
19967            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19968        if !text_highlights.1.is_empty() {
19969            self.scrollbar_marker_state.dirty = true;
19970            cx.notify();
19971        }
19972        Some(text_highlights)
19973    }
19974
19975    pub fn highlight_gutter<T: 'static>(
19976        &mut self,
19977        ranges: impl Into<Vec<Range<Anchor>>>,
19978        color_fetcher: fn(&App) -> Hsla,
19979        cx: &mut Context<Self>,
19980    ) {
19981        self.gutter_highlights
19982            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19983        cx.notify();
19984    }
19985
19986    pub fn clear_gutter_highlights<T: 'static>(
19987        &mut self,
19988        cx: &mut Context<Self>,
19989    ) -> Option<GutterHighlight> {
19990        cx.notify();
19991        self.gutter_highlights.remove(&TypeId::of::<T>())
19992    }
19993
19994    pub fn insert_gutter_highlight<T: 'static>(
19995        &mut self,
19996        range: Range<Anchor>,
19997        color_fetcher: fn(&App) -> Hsla,
19998        cx: &mut Context<Self>,
19999    ) {
20000        let snapshot = self.buffer().read(cx).snapshot(cx);
20001        let mut highlights = self
20002            .gutter_highlights
20003            .remove(&TypeId::of::<T>())
20004            .map(|(_, highlights)| highlights)
20005            .unwrap_or_default();
20006        let ix = highlights.binary_search_by(|highlight| {
20007            Ordering::Equal
20008                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20009                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20010        });
20011        if let Err(ix) = ix {
20012            highlights.insert(ix, range);
20013        }
20014        self.gutter_highlights
20015            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20016    }
20017
20018    pub fn remove_gutter_highlights<T: 'static>(
20019        &mut self,
20020        ranges_to_remove: Vec<Range<Anchor>>,
20021        cx: &mut Context<Self>,
20022    ) {
20023        let snapshot = self.buffer().read(cx).snapshot(cx);
20024        let Some((color_fetcher, mut gutter_highlights)) =
20025            self.gutter_highlights.remove(&TypeId::of::<T>())
20026        else {
20027            return;
20028        };
20029        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20030        gutter_highlights.retain(|highlight| {
20031            while let Some(range_to_remove) = ranges_to_remove.peek() {
20032                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20033                    Ordering::Less | Ordering::Equal => {
20034                        ranges_to_remove.next();
20035                    }
20036                    Ordering::Greater => {
20037                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20038                            Ordering::Less | Ordering::Equal => {
20039                                return false;
20040                            }
20041                            Ordering::Greater => break,
20042                        }
20043                    }
20044                }
20045            }
20046
20047            true
20048        });
20049        self.gutter_highlights
20050            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20051    }
20052
20053    #[cfg(feature = "test-support")]
20054    pub fn all_text_highlights(
20055        &self,
20056        window: &mut Window,
20057        cx: &mut Context<Self>,
20058    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20059        let snapshot = self.snapshot(window, cx);
20060        self.display_map.update(cx, |display_map, _| {
20061            display_map
20062                .all_text_highlights()
20063                .map(|highlight| {
20064                    let (style, ranges) = highlight.as_ref();
20065                    (
20066                        *style,
20067                        ranges
20068                            .iter()
20069                            .map(|range| range.clone().to_display_points(&snapshot))
20070                            .collect(),
20071                    )
20072                })
20073                .collect()
20074        })
20075    }
20076
20077    #[cfg(feature = "test-support")]
20078    pub fn all_text_background_highlights(
20079        &self,
20080        window: &mut Window,
20081        cx: &mut Context<Self>,
20082    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20083        let snapshot = self.snapshot(window, cx);
20084        let buffer = &snapshot.buffer_snapshot;
20085        let start = buffer.anchor_before(0);
20086        let end = buffer.anchor_after(buffer.len());
20087        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20088    }
20089
20090    #[cfg(any(test, feature = "test-support"))]
20091    pub fn sorted_background_highlights_in_range(
20092        &self,
20093        search_range: Range<Anchor>,
20094        display_snapshot: &DisplaySnapshot,
20095        theme: &Theme,
20096    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20097        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20098        res.sort_by(|a, b| {
20099            a.0.start
20100                .cmp(&b.0.start)
20101                .then_with(|| a.0.end.cmp(&b.0.end))
20102                .then_with(|| a.1.cmp(&b.1))
20103        });
20104        res
20105    }
20106
20107    #[cfg(feature = "test-support")]
20108    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20109        let snapshot = self.buffer().read(cx).snapshot(cx);
20110
20111        let highlights = self
20112            .background_highlights
20113            .get(&HighlightKey::Type(TypeId::of::<
20114                items::BufferSearchHighlights,
20115            >()));
20116
20117        if let Some((_color, ranges)) = highlights {
20118            ranges
20119                .iter()
20120                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20121                .collect_vec()
20122        } else {
20123            vec![]
20124        }
20125    }
20126
20127    fn document_highlights_for_position<'a>(
20128        &'a self,
20129        position: Anchor,
20130        buffer: &'a MultiBufferSnapshot,
20131    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20132        let read_highlights = self
20133            .background_highlights
20134            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20135            .map(|h| &h.1);
20136        let write_highlights = self
20137            .background_highlights
20138            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20139            .map(|h| &h.1);
20140        let left_position = position.bias_left(buffer);
20141        let right_position = position.bias_right(buffer);
20142        read_highlights
20143            .into_iter()
20144            .chain(write_highlights)
20145            .flat_map(move |ranges| {
20146                let start_ix = match ranges.binary_search_by(|probe| {
20147                    let cmp = probe.end.cmp(&left_position, buffer);
20148                    if cmp.is_ge() {
20149                        Ordering::Greater
20150                    } else {
20151                        Ordering::Less
20152                    }
20153                }) {
20154                    Ok(i) | Err(i) => i,
20155                };
20156
20157                ranges[start_ix..]
20158                    .iter()
20159                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20160            })
20161    }
20162
20163    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20164        self.background_highlights
20165            .get(&HighlightKey::Type(TypeId::of::<T>()))
20166            .is_some_and(|(_, highlights)| !highlights.is_empty())
20167    }
20168
20169    /// Returns all background highlights for a given range.
20170    ///
20171    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20172    pub fn background_highlights_in_range(
20173        &self,
20174        search_range: Range<Anchor>,
20175        display_snapshot: &DisplaySnapshot,
20176        theme: &Theme,
20177    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20178        let mut results = Vec::new();
20179        for (color_fetcher, ranges) in self.background_highlights.values() {
20180            let color = color_fetcher(theme);
20181            let start_ix = match ranges.binary_search_by(|probe| {
20182                let cmp = probe
20183                    .end
20184                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20185                if cmp.is_gt() {
20186                    Ordering::Greater
20187                } else {
20188                    Ordering::Less
20189                }
20190            }) {
20191                Ok(i) | Err(i) => i,
20192            };
20193            for range in &ranges[start_ix..] {
20194                if range
20195                    .start
20196                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20197                    .is_ge()
20198                {
20199                    break;
20200                }
20201
20202                let start = range.start.to_display_point(display_snapshot);
20203                let end = range.end.to_display_point(display_snapshot);
20204                results.push((start..end, color))
20205            }
20206        }
20207        results
20208    }
20209
20210    pub fn gutter_highlights_in_range(
20211        &self,
20212        search_range: Range<Anchor>,
20213        display_snapshot: &DisplaySnapshot,
20214        cx: &App,
20215    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20216        let mut results = Vec::new();
20217        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20218            let color = color_fetcher(cx);
20219            let start_ix = match ranges.binary_search_by(|probe| {
20220                let cmp = probe
20221                    .end
20222                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
20223                if cmp.is_gt() {
20224                    Ordering::Greater
20225                } else {
20226                    Ordering::Less
20227                }
20228            }) {
20229                Ok(i) | Err(i) => i,
20230            };
20231            for range in &ranges[start_ix..] {
20232                if range
20233                    .start
20234                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
20235                    .is_ge()
20236                {
20237                    break;
20238                }
20239
20240                let start = range.start.to_display_point(display_snapshot);
20241                let end = range.end.to_display_point(display_snapshot);
20242                results.push((start..end, color))
20243            }
20244        }
20245        results
20246    }
20247
20248    /// Get the text ranges corresponding to the redaction query
20249    pub fn redacted_ranges(
20250        &self,
20251        search_range: Range<Anchor>,
20252        display_snapshot: &DisplaySnapshot,
20253        cx: &App,
20254    ) -> Vec<Range<DisplayPoint>> {
20255        display_snapshot
20256            .buffer_snapshot
20257            .redacted_ranges(search_range, |file| {
20258                if let Some(file) = file {
20259                    file.is_private()
20260                        && EditorSettings::get(
20261                            Some(SettingsLocation {
20262                                worktree_id: file.worktree_id(cx),
20263                                path: file.path().as_ref(),
20264                            }),
20265                            cx,
20266                        )
20267                        .redact_private_values
20268                } else {
20269                    false
20270                }
20271            })
20272            .map(|range| {
20273                range.start.to_display_point(display_snapshot)
20274                    ..range.end.to_display_point(display_snapshot)
20275            })
20276            .collect()
20277    }
20278
20279    pub fn highlight_text_key<T: 'static>(
20280        &mut self,
20281        key: usize,
20282        ranges: Vec<Range<Anchor>>,
20283        style: HighlightStyle,
20284        cx: &mut Context<Self>,
20285    ) {
20286        self.display_map.update(cx, |map, _| {
20287            map.highlight_text(
20288                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20289                ranges,
20290                style,
20291            );
20292        });
20293        cx.notify();
20294    }
20295
20296    pub fn highlight_text<T: 'static>(
20297        &mut self,
20298        ranges: Vec<Range<Anchor>>,
20299        style: HighlightStyle,
20300        cx: &mut Context<Self>,
20301    ) {
20302        self.display_map.update(cx, |map, _| {
20303            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20304        });
20305        cx.notify();
20306    }
20307
20308    pub(crate) fn highlight_inlays<T: 'static>(
20309        &mut self,
20310        highlights: Vec<InlayHighlight>,
20311        style: HighlightStyle,
20312        cx: &mut Context<Self>,
20313    ) {
20314        self.display_map.update(cx, |map, _| {
20315            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
20316        });
20317        cx.notify();
20318    }
20319
20320    pub fn text_highlights<'a, T: 'static>(
20321        &'a self,
20322        cx: &'a App,
20323    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20324        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20325    }
20326
20327    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20328        let cleared = self
20329            .display_map
20330            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20331        if cleared {
20332            cx.notify();
20333        }
20334    }
20335
20336    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20337        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20338            && self.focus_handle.is_focused(window)
20339    }
20340
20341    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20342        self.show_cursor_when_unfocused = is_enabled;
20343        cx.notify();
20344    }
20345
20346    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20347        cx.notify();
20348    }
20349
20350    fn on_debug_session_event(
20351        &mut self,
20352        _session: Entity<Session>,
20353        event: &SessionEvent,
20354        cx: &mut Context<Self>,
20355    ) {
20356        if let SessionEvent::InvalidateInlineValue = event {
20357            self.refresh_inline_values(cx);
20358        }
20359    }
20360
20361    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20362        let Some(project) = self.project.clone() else {
20363            return;
20364        };
20365
20366        if !self.inline_value_cache.enabled {
20367            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20368            self.splice_inlays(&inlays, Vec::new(), cx);
20369            return;
20370        }
20371
20372        let current_execution_position = self
20373            .highlighted_rows
20374            .get(&TypeId::of::<ActiveDebugLine>())
20375            .and_then(|lines| lines.last().map(|line| line.range.end));
20376
20377        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20378            let inline_values = editor
20379                .update(cx, |editor, cx| {
20380                    let Some(current_execution_position) = current_execution_position else {
20381                        return Some(Task::ready(Ok(Vec::new())));
20382                    };
20383
20384                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20385                        let snapshot = buffer.snapshot(cx);
20386
20387                        let excerpt = snapshot.excerpt_containing(
20388                            current_execution_position..current_execution_position,
20389                        )?;
20390
20391                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20392                    })?;
20393
20394                    let range =
20395                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20396
20397                    project.inline_values(buffer, range, cx)
20398                })
20399                .ok()
20400                .flatten()?
20401                .await
20402                .context("refreshing debugger inlays")
20403                .log_err()?;
20404
20405            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20406
20407            for (buffer_id, inline_value) in inline_values
20408                .into_iter()
20409                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20410            {
20411                buffer_inline_values
20412                    .entry(buffer_id)
20413                    .or_default()
20414                    .push(inline_value);
20415            }
20416
20417            editor
20418                .update(cx, |editor, cx| {
20419                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20420                    let mut new_inlays = Vec::default();
20421
20422                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20423                        let buffer_id = buffer_snapshot.remote_id();
20424                        buffer_inline_values
20425                            .get(&buffer_id)
20426                            .into_iter()
20427                            .flatten()
20428                            .for_each(|hint| {
20429                                let inlay = Inlay::debugger(
20430                                    post_inc(&mut editor.next_inlay_id),
20431                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20432                                    hint.text(),
20433                                );
20434                                if !inlay.text.chars().contains(&'\n') {
20435                                    new_inlays.push(inlay);
20436                                }
20437                            });
20438                    }
20439
20440                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20441                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20442
20443                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20444                })
20445                .ok()?;
20446            Some(())
20447        });
20448    }
20449
20450    fn on_buffer_event(
20451        &mut self,
20452        multibuffer: &Entity<MultiBuffer>,
20453        event: &multi_buffer::Event,
20454        window: &mut Window,
20455        cx: &mut Context<Self>,
20456    ) {
20457        match event {
20458            multi_buffer::Event::Edited {
20459                singleton_buffer_edited,
20460                edited_buffer,
20461            } => {
20462                self.scrollbar_marker_state.dirty = true;
20463                self.active_indent_guides_state.dirty = true;
20464                self.refresh_active_diagnostics(cx);
20465                self.refresh_code_actions(window, cx);
20466                self.refresh_selected_text_highlights(true, window, cx);
20467                self.refresh_single_line_folds(window, cx);
20468                refresh_matching_bracket_highlights(self, window, cx);
20469                if self.has_active_edit_prediction() {
20470                    self.update_visible_edit_prediction(window, cx);
20471                }
20472                if let Some(project) = self.project.as_ref()
20473                    && let Some(edited_buffer) = edited_buffer
20474                {
20475                    project.update(cx, |project, cx| {
20476                        self.registered_buffers
20477                            .entry(edited_buffer.read(cx).remote_id())
20478                            .or_insert_with(|| {
20479                                project.register_buffer_with_language_servers(edited_buffer, cx)
20480                            });
20481                    });
20482                }
20483                cx.emit(EditorEvent::BufferEdited);
20484                cx.emit(SearchEvent::MatchesInvalidated);
20485
20486                if let Some(buffer) = edited_buffer {
20487                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20488                }
20489
20490                if *singleton_buffer_edited {
20491                    if let Some(buffer) = edited_buffer
20492                        && buffer.read(cx).file().is_none()
20493                    {
20494                        cx.emit(EditorEvent::TitleChanged);
20495                    }
20496                    if let Some(project) = &self.project {
20497                        #[allow(clippy::mutable_key_type)]
20498                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20499                            multibuffer
20500                                .all_buffers()
20501                                .into_iter()
20502                                .filter_map(|buffer| {
20503                                    buffer.update(cx, |buffer, cx| {
20504                                        let language = buffer.language()?;
20505                                        let should_discard = project.update(cx, |project, cx| {
20506                                            project.is_local()
20507                                                && !project.has_language_servers_for(buffer, cx)
20508                                        });
20509                                        should_discard.not().then_some(language.clone())
20510                                    })
20511                                })
20512                                .collect::<HashSet<_>>()
20513                        });
20514                        if !languages_affected.is_empty() {
20515                            self.refresh_inlay_hints(
20516                                InlayHintRefreshReason::BufferEdited(languages_affected),
20517                                cx,
20518                            );
20519                        }
20520                    }
20521                }
20522
20523                let Some(project) = &self.project else { return };
20524                let (telemetry, is_via_ssh) = {
20525                    let project = project.read(cx);
20526                    let telemetry = project.client().telemetry().clone();
20527                    let is_via_ssh = project.is_via_remote_server();
20528                    (telemetry, is_via_ssh)
20529                };
20530                refresh_linked_ranges(self, window, cx);
20531                telemetry.log_edit_event("editor", is_via_ssh);
20532            }
20533            multi_buffer::Event::ExcerptsAdded {
20534                buffer,
20535                predecessor,
20536                excerpts,
20537            } => {
20538                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20539                let buffer_id = buffer.read(cx).remote_id();
20540                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20541                    && let Some(project) = &self.project
20542                {
20543                    update_uncommitted_diff_for_buffer(
20544                        cx.entity(),
20545                        project,
20546                        [buffer.clone()],
20547                        self.buffer.clone(),
20548                        cx,
20549                    )
20550                    .detach();
20551                }
20552                if self.active_diagnostics != ActiveDiagnostic::All {
20553                    self.update_lsp_data(false, Some(buffer_id), window, cx);
20554                }
20555                cx.emit(EditorEvent::ExcerptsAdded {
20556                    buffer: buffer.clone(),
20557                    predecessor: *predecessor,
20558                    excerpts: excerpts.clone(),
20559                });
20560                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20561            }
20562            multi_buffer::Event::ExcerptsRemoved {
20563                ids,
20564                removed_buffer_ids,
20565            } => {
20566                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20567                let buffer = self.buffer.read(cx);
20568                self.registered_buffers
20569                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20570                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20571                cx.emit(EditorEvent::ExcerptsRemoved {
20572                    ids: ids.clone(),
20573                    removed_buffer_ids: removed_buffer_ids.clone(),
20574                });
20575            }
20576            multi_buffer::Event::ExcerptsEdited {
20577                excerpt_ids,
20578                buffer_ids,
20579            } => {
20580                self.display_map.update(cx, |map, cx| {
20581                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20582                });
20583                cx.emit(EditorEvent::ExcerptsEdited {
20584                    ids: excerpt_ids.clone(),
20585                });
20586            }
20587            multi_buffer::Event::ExcerptsExpanded { ids } => {
20588                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20589                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20590            }
20591            multi_buffer::Event::Reparsed(buffer_id) => {
20592                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20593                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20594
20595                cx.emit(EditorEvent::Reparsed(*buffer_id));
20596            }
20597            multi_buffer::Event::DiffHunksToggled => {
20598                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20599            }
20600            multi_buffer::Event::LanguageChanged(buffer_id) => {
20601                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20602                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20603                cx.emit(EditorEvent::Reparsed(*buffer_id));
20604                cx.notify();
20605            }
20606            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20607            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20608            multi_buffer::Event::FileHandleChanged
20609            | multi_buffer::Event::Reloaded
20610            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20611            multi_buffer::Event::DiagnosticsUpdated => {
20612                self.update_diagnostics_state(window, cx);
20613            }
20614            _ => {}
20615        };
20616    }
20617
20618    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20619        if !self.diagnostics_enabled() {
20620            return;
20621        }
20622        self.refresh_active_diagnostics(cx);
20623        self.refresh_inline_diagnostics(true, window, cx);
20624        self.scrollbar_marker_state.dirty = true;
20625        cx.notify();
20626    }
20627
20628    pub fn start_temporary_diff_override(&mut self) {
20629        self.load_diff_task.take();
20630        self.temporary_diff_override = true;
20631    }
20632
20633    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20634        self.temporary_diff_override = false;
20635        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20636        self.buffer.update(cx, |buffer, cx| {
20637            buffer.set_all_diff_hunks_collapsed(cx);
20638        });
20639
20640        if let Some(project) = self.project.clone() {
20641            self.load_diff_task = Some(
20642                update_uncommitted_diff_for_buffer(
20643                    cx.entity(),
20644                    &project,
20645                    self.buffer.read(cx).all_buffers(),
20646                    self.buffer.clone(),
20647                    cx,
20648                )
20649                .shared(),
20650            );
20651        }
20652    }
20653
20654    fn on_display_map_changed(
20655        &mut self,
20656        _: Entity<DisplayMap>,
20657        _: &mut Window,
20658        cx: &mut Context<Self>,
20659    ) {
20660        cx.notify();
20661    }
20662
20663    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20664        if self.diagnostics_enabled() {
20665            let new_severity = EditorSettings::get_global(cx)
20666                .diagnostics_max_severity
20667                .unwrap_or(DiagnosticSeverity::Hint);
20668            self.set_max_diagnostics_severity(new_severity, cx);
20669        }
20670        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20671        self.update_edit_prediction_settings(cx);
20672        self.refresh_edit_prediction(true, false, window, cx);
20673        self.refresh_inline_values(cx);
20674        self.refresh_inlay_hints(
20675            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20676                self.selections.newest_anchor().head(),
20677                &self.buffer.read(cx).snapshot(cx),
20678                cx,
20679            )),
20680            cx,
20681        );
20682
20683        let old_cursor_shape = self.cursor_shape;
20684        let old_show_breadcrumbs = self.show_breadcrumbs;
20685
20686        {
20687            let editor_settings = EditorSettings::get_global(cx);
20688            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20689            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20690            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20691            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20692        }
20693
20694        if old_cursor_shape != self.cursor_shape {
20695            cx.emit(EditorEvent::CursorShapeChanged);
20696        }
20697
20698        if old_show_breadcrumbs != self.show_breadcrumbs {
20699            cx.emit(EditorEvent::BreadcrumbsChanged);
20700        }
20701
20702        let project_settings = ProjectSettings::get_global(cx);
20703        self.serialize_dirty_buffers =
20704            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20705
20706        if self.mode.is_full() {
20707            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20708            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20709            if self.show_inline_diagnostics != show_inline_diagnostics {
20710                self.show_inline_diagnostics = show_inline_diagnostics;
20711                self.refresh_inline_diagnostics(false, window, cx);
20712            }
20713
20714            if self.git_blame_inline_enabled != inline_blame_enabled {
20715                self.toggle_git_blame_inline_internal(false, window, cx);
20716            }
20717
20718            let minimap_settings = EditorSettings::get_global(cx).minimap;
20719            if self.minimap_visibility != MinimapVisibility::Disabled {
20720                if self.minimap_visibility.settings_visibility()
20721                    != minimap_settings.minimap_enabled()
20722                {
20723                    self.set_minimap_visibility(
20724                        MinimapVisibility::for_mode(self.mode(), cx),
20725                        window,
20726                        cx,
20727                    );
20728                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20729                    minimap_entity.update(cx, |minimap_editor, cx| {
20730                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20731                    })
20732                }
20733            }
20734        }
20735
20736        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20737            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20738        }) {
20739            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20740                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20741            }
20742            self.refresh_colors(false, None, window, cx);
20743        }
20744
20745        cx.notify();
20746    }
20747
20748    pub fn set_searchable(&mut self, searchable: bool) {
20749        self.searchable = searchable;
20750    }
20751
20752    pub fn searchable(&self) -> bool {
20753        self.searchable
20754    }
20755
20756    fn open_proposed_changes_editor(
20757        &mut self,
20758        _: &OpenProposedChangesEditor,
20759        window: &mut Window,
20760        cx: &mut Context<Self>,
20761    ) {
20762        let Some(workspace) = self.workspace() else {
20763            cx.propagate();
20764            return;
20765        };
20766
20767        let selections = self.selections.all::<usize>(cx);
20768        let multi_buffer = self.buffer.read(cx);
20769        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20770        let mut new_selections_by_buffer = HashMap::default();
20771        for selection in selections {
20772            for (buffer, range, _) in
20773                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20774            {
20775                let mut range = range.to_point(buffer);
20776                range.start.column = 0;
20777                range.end.column = buffer.line_len(range.end.row);
20778                new_selections_by_buffer
20779                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20780                    .or_insert(Vec::new())
20781                    .push(range)
20782            }
20783        }
20784
20785        let proposed_changes_buffers = new_selections_by_buffer
20786            .into_iter()
20787            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20788            .collect::<Vec<_>>();
20789        let proposed_changes_editor = cx.new(|cx| {
20790            ProposedChangesEditor::new(
20791                "Proposed changes",
20792                proposed_changes_buffers,
20793                self.project.clone(),
20794                window,
20795                cx,
20796            )
20797        });
20798
20799        window.defer(cx, move |window, cx| {
20800            workspace.update(cx, |workspace, cx| {
20801                workspace.active_pane().update(cx, |pane, cx| {
20802                    pane.add_item(
20803                        Box::new(proposed_changes_editor),
20804                        true,
20805                        true,
20806                        None,
20807                        window,
20808                        cx,
20809                    );
20810                });
20811            });
20812        });
20813    }
20814
20815    pub fn open_excerpts_in_split(
20816        &mut self,
20817        _: &OpenExcerptsSplit,
20818        window: &mut Window,
20819        cx: &mut Context<Self>,
20820    ) {
20821        self.open_excerpts_common(None, true, window, cx)
20822    }
20823
20824    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20825        self.open_excerpts_common(None, false, window, cx)
20826    }
20827
20828    fn open_excerpts_common(
20829        &mut self,
20830        jump_data: Option<JumpData>,
20831        split: bool,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        let Some(workspace) = self.workspace() else {
20836            cx.propagate();
20837            return;
20838        };
20839
20840        if self.buffer.read(cx).is_singleton() {
20841            cx.propagate();
20842            return;
20843        }
20844
20845        let mut new_selections_by_buffer = HashMap::default();
20846        match &jump_data {
20847            Some(JumpData::MultiBufferPoint {
20848                excerpt_id,
20849                position,
20850                anchor,
20851                line_offset_from_top,
20852            }) => {
20853                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20854                if let Some(buffer) = multi_buffer_snapshot
20855                    .buffer_id_for_excerpt(*excerpt_id)
20856                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20857                {
20858                    let buffer_snapshot = buffer.read(cx).snapshot();
20859                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20860                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20861                    } else {
20862                        buffer_snapshot.clip_point(*position, Bias::Left)
20863                    };
20864                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20865                    new_selections_by_buffer.insert(
20866                        buffer,
20867                        (
20868                            vec![jump_to_offset..jump_to_offset],
20869                            Some(*line_offset_from_top),
20870                        ),
20871                    );
20872                }
20873            }
20874            Some(JumpData::MultiBufferRow {
20875                row,
20876                line_offset_from_top,
20877            }) => {
20878                let point = MultiBufferPoint::new(row.0, 0);
20879                if let Some((buffer, buffer_point, _)) =
20880                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20881                {
20882                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20883                    new_selections_by_buffer
20884                        .entry(buffer)
20885                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20886                        .0
20887                        .push(buffer_offset..buffer_offset)
20888                }
20889            }
20890            None => {
20891                let selections = self.selections.all::<usize>(cx);
20892                let multi_buffer = self.buffer.read(cx);
20893                for selection in selections {
20894                    for (snapshot, range, _, anchor) in multi_buffer
20895                        .snapshot(cx)
20896                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20897                    {
20898                        if let Some(anchor) = anchor {
20899                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
20900                            else {
20901                                continue;
20902                            };
20903                            let offset = text::ToOffset::to_offset(
20904                                &anchor.text_anchor,
20905                                &buffer_handle.read(cx).snapshot(),
20906                            );
20907                            let range = offset..offset;
20908                            new_selections_by_buffer
20909                                .entry(buffer_handle)
20910                                .or_insert((Vec::new(), None))
20911                                .0
20912                                .push(range)
20913                        } else {
20914                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20915                            else {
20916                                continue;
20917                            };
20918                            new_selections_by_buffer
20919                                .entry(buffer_handle)
20920                                .or_insert((Vec::new(), None))
20921                                .0
20922                                .push(range)
20923                        }
20924                    }
20925                }
20926            }
20927        }
20928
20929        new_selections_by_buffer
20930            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20931
20932        if new_selections_by_buffer.is_empty() {
20933            return;
20934        }
20935
20936        // We defer the pane interaction because we ourselves are a workspace item
20937        // and activating a new item causes the pane to call a method on us reentrantly,
20938        // which panics if we're on the stack.
20939        window.defer(cx, move |window, cx| {
20940            workspace.update(cx, |workspace, cx| {
20941                let pane = if split {
20942                    workspace.adjacent_pane(window, cx)
20943                } else {
20944                    workspace.active_pane().clone()
20945                };
20946
20947                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20948                    let editor = buffer
20949                        .read(cx)
20950                        .file()
20951                        .is_none()
20952                        .then(|| {
20953                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20954                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20955                            // Instead, we try to activate the existing editor in the pane first.
20956                            let (editor, pane_item_index) =
20957                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20958                                    let editor = item.downcast::<Editor>()?;
20959                                    let singleton_buffer =
20960                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20961                                    if singleton_buffer == buffer {
20962                                        Some((editor, i))
20963                                    } else {
20964                                        None
20965                                    }
20966                                })?;
20967                            pane.update(cx, |pane, cx| {
20968                                pane.activate_item(pane_item_index, true, true, window, cx)
20969                            });
20970                            Some(editor)
20971                        })
20972                        .flatten()
20973                        .unwrap_or_else(|| {
20974                            workspace.open_project_item::<Self>(
20975                                pane.clone(),
20976                                buffer,
20977                                true,
20978                                true,
20979                                window,
20980                                cx,
20981                            )
20982                        });
20983
20984                    editor.update(cx, |editor, cx| {
20985                        let autoscroll = match scroll_offset {
20986                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20987                            None => Autoscroll::newest(),
20988                        };
20989                        let nav_history = editor.nav_history.take();
20990                        editor.change_selections(
20991                            SelectionEffects::scroll(autoscroll),
20992                            window,
20993                            cx,
20994                            |s| {
20995                                s.select_ranges(ranges);
20996                            },
20997                        );
20998                        editor.nav_history = nav_history;
20999                    });
21000                }
21001            })
21002        });
21003    }
21004
21005    // For now, don't allow opening excerpts in buffers that aren't backed by
21006    // regular project files.
21007    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21008        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21009    }
21010
21011    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21012        let snapshot = self.buffer.read(cx).read(cx);
21013        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21014        Some(
21015            ranges
21016                .iter()
21017                .map(move |range| {
21018                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21019                })
21020                .collect(),
21021        )
21022    }
21023
21024    fn selection_replacement_ranges(
21025        &self,
21026        range: Range<OffsetUtf16>,
21027        cx: &mut App,
21028    ) -> Vec<Range<OffsetUtf16>> {
21029        let selections = self.selections.all::<OffsetUtf16>(cx);
21030        let newest_selection = selections
21031            .iter()
21032            .max_by_key(|selection| selection.id)
21033            .unwrap();
21034        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21035        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21036        let snapshot = self.buffer.read(cx).read(cx);
21037        selections
21038            .into_iter()
21039            .map(|mut selection| {
21040                selection.start.0 =
21041                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21042                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21043                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21044                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21045            })
21046            .collect()
21047    }
21048
21049    fn report_editor_event(
21050        &self,
21051        reported_event: ReportEditorEvent,
21052        file_extension: Option<String>,
21053        cx: &App,
21054    ) {
21055        if cfg!(any(test, feature = "test-support")) {
21056            return;
21057        }
21058
21059        let Some(project) = &self.project else { return };
21060
21061        // If None, we are in a file without an extension
21062        let file = self
21063            .buffer
21064            .read(cx)
21065            .as_singleton()
21066            .and_then(|b| b.read(cx).file());
21067        let file_extension = file_extension.or(file
21068            .as_ref()
21069            .and_then(|file| Path::new(file.file_name(cx)).extension())
21070            .and_then(|e| e.to_str())
21071            .map(|a| a.to_string()));
21072
21073        let vim_mode = vim_enabled(cx);
21074
21075        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21076        let copilot_enabled = edit_predictions_provider
21077            == language::language_settings::EditPredictionProvider::Copilot;
21078        let copilot_enabled_for_language = self
21079            .buffer
21080            .read(cx)
21081            .language_settings(cx)
21082            .show_edit_predictions;
21083
21084        let project = project.read(cx);
21085        let event_type = reported_event.event_type();
21086
21087        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21088            telemetry::event!(
21089                event_type,
21090                type = if auto_saved {"autosave"} else {"manual"},
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        } else {
21099            telemetry::event!(
21100                event_type,
21101                file_extension,
21102                vim_mode,
21103                copilot_enabled,
21104                copilot_enabled_for_language,
21105                edit_predictions_provider,
21106                is_via_ssh = project.is_via_remote_server(),
21107            );
21108        };
21109    }
21110
21111    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21112    /// with each line being an array of {text, highlight} objects.
21113    fn copy_highlight_json(
21114        &mut self,
21115        _: &CopyHighlightJson,
21116        window: &mut Window,
21117        cx: &mut Context<Self>,
21118    ) {
21119        #[derive(Serialize)]
21120        struct Chunk<'a> {
21121            text: String,
21122            highlight: Option<&'a str>,
21123        }
21124
21125        let snapshot = self.buffer.read(cx).snapshot(cx);
21126        let range = self
21127            .selected_text_range(false, window, cx)
21128            .and_then(|selection| {
21129                if selection.range.is_empty() {
21130                    None
21131                } else {
21132                    Some(selection.range)
21133                }
21134            })
21135            .unwrap_or_else(|| 0..snapshot.len());
21136
21137        let chunks = snapshot.chunks(range, true);
21138        let mut lines = Vec::new();
21139        let mut line: VecDeque<Chunk> = VecDeque::new();
21140
21141        let Some(style) = self.style.as_ref() else {
21142            return;
21143        };
21144
21145        for chunk in chunks {
21146            let highlight = chunk
21147                .syntax_highlight_id
21148                .and_then(|id| id.name(&style.syntax));
21149            let mut chunk_lines = chunk.text.split('\n').peekable();
21150            while let Some(text) = chunk_lines.next() {
21151                let mut merged_with_last_token = false;
21152                if let Some(last_token) = line.back_mut()
21153                    && last_token.highlight == highlight
21154                {
21155                    last_token.text.push_str(text);
21156                    merged_with_last_token = true;
21157                }
21158
21159                if !merged_with_last_token {
21160                    line.push_back(Chunk {
21161                        text: text.into(),
21162                        highlight,
21163                    });
21164                }
21165
21166                if chunk_lines.peek().is_some() {
21167                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21168                        line.pop_front();
21169                    }
21170                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21171                        line.pop_back();
21172                    }
21173
21174                    lines.push(mem::take(&mut line));
21175                }
21176            }
21177        }
21178
21179        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21180            return;
21181        };
21182        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21183    }
21184
21185    pub fn open_context_menu(
21186        &mut self,
21187        _: &OpenContextMenu,
21188        window: &mut Window,
21189        cx: &mut Context<Self>,
21190    ) {
21191        self.request_autoscroll(Autoscroll::newest(), cx);
21192        let position = self.selections.newest_display(cx).start;
21193        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21194    }
21195
21196    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
21197        &self.inlay_hint_cache
21198    }
21199
21200    pub fn replay_insert_event(
21201        &mut self,
21202        text: &str,
21203        relative_utf16_range: Option<Range<isize>>,
21204        window: &mut Window,
21205        cx: &mut Context<Self>,
21206    ) {
21207        if !self.input_enabled {
21208            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21209            return;
21210        }
21211        if let Some(relative_utf16_range) = relative_utf16_range {
21212            let selections = self.selections.all::<OffsetUtf16>(cx);
21213            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21214                let new_ranges = selections.into_iter().map(|range| {
21215                    let start = OffsetUtf16(
21216                        range
21217                            .head()
21218                            .0
21219                            .saturating_add_signed(relative_utf16_range.start),
21220                    );
21221                    let end = OffsetUtf16(
21222                        range
21223                            .head()
21224                            .0
21225                            .saturating_add_signed(relative_utf16_range.end),
21226                    );
21227                    start..end
21228                });
21229                s.select_ranges(new_ranges);
21230            });
21231        }
21232
21233        self.handle_input(text, window, cx);
21234    }
21235
21236    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
21237        let Some(provider) = self.semantics_provider.as_ref() else {
21238            return false;
21239        };
21240
21241        let mut supports = false;
21242        self.buffer().update(cx, |this, cx| {
21243            this.for_each_buffer(|buffer| {
21244                supports |= provider.supports_inlay_hints(buffer, cx);
21245            });
21246        });
21247
21248        supports
21249    }
21250
21251    pub fn is_focused(&self, window: &Window) -> bool {
21252        self.focus_handle.is_focused(window)
21253    }
21254
21255    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21256        cx.emit(EditorEvent::Focused);
21257
21258        if let Some(descendant) = self
21259            .last_focused_descendant
21260            .take()
21261            .and_then(|descendant| descendant.upgrade())
21262        {
21263            window.focus(&descendant);
21264        } else {
21265            if let Some(blame) = self.blame.as_ref() {
21266                blame.update(cx, GitBlame::focus)
21267            }
21268
21269            self.blink_manager.update(cx, BlinkManager::enable);
21270            self.show_cursor_names(window, cx);
21271            self.buffer.update(cx, |buffer, cx| {
21272                buffer.finalize_last_transaction(cx);
21273                if self.leader_id.is_none() {
21274                    buffer.set_active_selections(
21275                        &self.selections.disjoint_anchors(),
21276                        self.selections.line_mode,
21277                        self.cursor_shape,
21278                        cx,
21279                    );
21280                }
21281            });
21282        }
21283    }
21284
21285    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21286        cx.emit(EditorEvent::FocusedIn)
21287    }
21288
21289    fn handle_focus_out(
21290        &mut self,
21291        event: FocusOutEvent,
21292        _window: &mut Window,
21293        cx: &mut Context<Self>,
21294    ) {
21295        if event.blurred != self.focus_handle {
21296            self.last_focused_descendant = Some(event.blurred);
21297        }
21298        self.selection_drag_state = SelectionDragState::None;
21299        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21300    }
21301
21302    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21303        self.blink_manager.update(cx, BlinkManager::disable);
21304        self.buffer
21305            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21306
21307        if let Some(blame) = self.blame.as_ref() {
21308            blame.update(cx, GitBlame::blur)
21309        }
21310        if !self.hover_state.focused(window, cx) {
21311            hide_hover(self, cx);
21312        }
21313        if !self
21314            .context_menu
21315            .borrow()
21316            .as_ref()
21317            .is_some_and(|context_menu| context_menu.focused(window, cx))
21318        {
21319            self.hide_context_menu(window, cx);
21320        }
21321        self.discard_edit_prediction(false, cx);
21322        cx.emit(EditorEvent::Blurred);
21323        cx.notify();
21324    }
21325
21326    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21327        let mut pending: String = window
21328            .pending_input_keystrokes()
21329            .into_iter()
21330            .flatten()
21331            .filter_map(|keystroke| {
21332                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21333                    keystroke.key_char.clone()
21334                } else {
21335                    None
21336                }
21337            })
21338            .collect();
21339
21340        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21341            pending = "".to_string();
21342        }
21343
21344        let existing_pending = self
21345            .text_highlights::<PendingInput>(cx)
21346            .map(|(_, ranges)| ranges.to_vec());
21347        if existing_pending.is_none() && pending.is_empty() {
21348            return;
21349        }
21350        let transaction =
21351            self.transact(window, cx, |this, window, cx| {
21352                let selections = this.selections.all::<usize>(cx);
21353                let edits = selections
21354                    .iter()
21355                    .map(|selection| (selection.end..selection.end, pending.clone()));
21356                this.edit(edits, cx);
21357                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21358                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21359                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21360                    }));
21361                });
21362                if let Some(existing_ranges) = existing_pending {
21363                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21364                    this.edit(edits, cx);
21365                }
21366            });
21367
21368        let snapshot = self.snapshot(window, cx);
21369        let ranges = self
21370            .selections
21371            .all::<usize>(cx)
21372            .into_iter()
21373            .map(|selection| {
21374                snapshot.buffer_snapshot.anchor_after(selection.end)
21375                    ..snapshot
21376                        .buffer_snapshot
21377                        .anchor_before(selection.end + pending.len())
21378            })
21379            .collect();
21380
21381        if pending.is_empty() {
21382            self.clear_highlights::<PendingInput>(cx);
21383        } else {
21384            self.highlight_text::<PendingInput>(
21385                ranges,
21386                HighlightStyle {
21387                    underline: Some(UnderlineStyle {
21388                        thickness: px(1.),
21389                        color: None,
21390                        wavy: false,
21391                    }),
21392                    ..Default::default()
21393                },
21394                cx,
21395            );
21396        }
21397
21398        self.ime_transaction = self.ime_transaction.or(transaction);
21399        if let Some(transaction) = self.ime_transaction {
21400            self.buffer.update(cx, |buffer, cx| {
21401                buffer.group_until_transaction(transaction, cx);
21402            });
21403        }
21404
21405        if self.text_highlights::<PendingInput>(cx).is_none() {
21406            self.ime_transaction.take();
21407        }
21408    }
21409
21410    pub fn register_action_renderer(
21411        &mut self,
21412        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21413    ) -> Subscription {
21414        let id = self.next_editor_action_id.post_inc();
21415        self.editor_actions
21416            .borrow_mut()
21417            .insert(id, Box::new(listener));
21418
21419        let editor_actions = self.editor_actions.clone();
21420        Subscription::new(move || {
21421            editor_actions.borrow_mut().remove(&id);
21422        })
21423    }
21424
21425    pub fn register_action<A: Action>(
21426        &mut self,
21427        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21428    ) -> Subscription {
21429        let id = self.next_editor_action_id.post_inc();
21430        let listener = Arc::new(listener);
21431        self.editor_actions.borrow_mut().insert(
21432            id,
21433            Box::new(move |_, window, _| {
21434                let listener = listener.clone();
21435                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21436                    let action = action.downcast_ref().unwrap();
21437                    if phase == DispatchPhase::Bubble {
21438                        listener(action, window, cx)
21439                    }
21440                })
21441            }),
21442        );
21443
21444        let editor_actions = self.editor_actions.clone();
21445        Subscription::new(move || {
21446            editor_actions.borrow_mut().remove(&id);
21447        })
21448    }
21449
21450    pub fn file_header_size(&self) -> u32 {
21451        FILE_HEADER_HEIGHT
21452    }
21453
21454    pub fn restore(
21455        &mut self,
21456        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21457        window: &mut Window,
21458        cx: &mut Context<Self>,
21459    ) {
21460        let workspace = self.workspace();
21461        let project = self.project();
21462        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21463            let mut tasks = Vec::new();
21464            for (buffer_id, changes) in revert_changes {
21465                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21466                    buffer.update(cx, |buffer, cx| {
21467                        buffer.edit(
21468                            changes
21469                                .into_iter()
21470                                .map(|(range, text)| (range, text.to_string())),
21471                            None,
21472                            cx,
21473                        );
21474                    });
21475
21476                    if let Some(project) =
21477                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21478                    {
21479                        project.update(cx, |project, cx| {
21480                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21481                        })
21482                    }
21483                }
21484            }
21485            tasks
21486        });
21487        cx.spawn_in(window, async move |_, cx| {
21488            for (buffer, task) in save_tasks {
21489                let result = task.await;
21490                if result.is_err() {
21491                    let Some(path) = buffer
21492                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21493                        .ok()
21494                    else {
21495                        continue;
21496                    };
21497                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21498                        let Some(task) = cx
21499                            .update_window_entity(workspace, |workspace, window, cx| {
21500                                workspace
21501                                    .open_path_preview(path, None, false, false, false, window, cx)
21502                            })
21503                            .ok()
21504                        else {
21505                            continue;
21506                        };
21507                        task.await.log_err();
21508                    }
21509                }
21510            }
21511        })
21512        .detach();
21513        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21514            selections.refresh()
21515        });
21516    }
21517
21518    pub fn to_pixel_point(
21519        &self,
21520        source: multi_buffer::Anchor,
21521        editor_snapshot: &EditorSnapshot,
21522        window: &mut Window,
21523    ) -> Option<gpui::Point<Pixels>> {
21524        let source_point = source.to_display_point(editor_snapshot);
21525        self.display_to_pixel_point(source_point, editor_snapshot, window)
21526    }
21527
21528    pub fn display_to_pixel_point(
21529        &self,
21530        source: DisplayPoint,
21531        editor_snapshot: &EditorSnapshot,
21532        window: &mut Window,
21533    ) -> Option<gpui::Point<Pixels>> {
21534        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21535        let text_layout_details = self.text_layout_details(window);
21536        let scroll_top = text_layout_details
21537            .scroll_anchor
21538            .scroll_position(editor_snapshot)
21539            .y;
21540
21541        if source.row().as_f32() < scroll_top.floor() {
21542            return None;
21543        }
21544        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21545        let source_y = line_height * (source.row().as_f32() - scroll_top);
21546        Some(gpui::Point::new(source_x, source_y))
21547    }
21548
21549    pub fn has_visible_completions_menu(&self) -> bool {
21550        !self.edit_prediction_preview_is_active()
21551            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21552                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21553            })
21554    }
21555
21556    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21557        if self.mode.is_minimap() {
21558            return;
21559        }
21560        self.addons
21561            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21562    }
21563
21564    pub fn unregister_addon<T: Addon>(&mut self) {
21565        self.addons.remove(&std::any::TypeId::of::<T>());
21566    }
21567
21568    pub fn addon<T: Addon>(&self) -> Option<&T> {
21569        let type_id = std::any::TypeId::of::<T>();
21570        self.addons
21571            .get(&type_id)
21572            .and_then(|item| item.to_any().downcast_ref::<T>())
21573    }
21574
21575    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21576        let type_id = std::any::TypeId::of::<T>();
21577        self.addons
21578            .get_mut(&type_id)
21579            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21580    }
21581
21582    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21583        let text_layout_details = self.text_layout_details(window);
21584        let style = &text_layout_details.editor_style;
21585        let font_id = window.text_system().resolve_font(&style.text.font());
21586        let font_size = style.text.font_size.to_pixels(window.rem_size());
21587        let line_height = style.text.line_height_in_pixels(window.rem_size());
21588        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21589        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21590
21591        CharacterDimensions {
21592            em_width,
21593            em_advance,
21594            line_height,
21595        }
21596    }
21597
21598    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21599        self.load_diff_task.clone()
21600    }
21601
21602    fn read_metadata_from_db(
21603        &mut self,
21604        item_id: u64,
21605        workspace_id: WorkspaceId,
21606        window: &mut Window,
21607        cx: &mut Context<Editor>,
21608    ) {
21609        if self.is_singleton(cx)
21610            && !self.mode.is_minimap()
21611            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21612        {
21613            let buffer_snapshot = OnceCell::new();
21614
21615            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21616                && !folds.is_empty()
21617            {
21618                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21619                self.fold_ranges(
21620                    folds
21621                        .into_iter()
21622                        .map(|(start, end)| {
21623                            snapshot.clip_offset(start, Bias::Left)
21624                                ..snapshot.clip_offset(end, Bias::Right)
21625                        })
21626                        .collect(),
21627                    false,
21628                    window,
21629                    cx,
21630                );
21631            }
21632
21633            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21634                && !selections.is_empty()
21635            {
21636                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21637                // skip adding the initial selection to selection history
21638                self.selection_history.mode = SelectionHistoryMode::Skipping;
21639                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21640                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21641                        snapshot.clip_offset(start, Bias::Left)
21642                            ..snapshot.clip_offset(end, Bias::Right)
21643                    }));
21644                });
21645                self.selection_history.mode = SelectionHistoryMode::Normal;
21646            };
21647        }
21648
21649        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21650    }
21651
21652    fn update_lsp_data(
21653        &mut self,
21654        ignore_cache: bool,
21655        for_buffer: Option<BufferId>,
21656        window: &mut Window,
21657        cx: &mut Context<'_, Self>,
21658    ) {
21659        self.pull_diagnostics(for_buffer, window, cx);
21660        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21661    }
21662}
21663
21664fn vim_enabled(cx: &App) -> bool {
21665    cx.global::<SettingsStore>()
21666        .raw_user_settings()
21667        .get("vim_mode")
21668        == Some(&serde_json::Value::Bool(true))
21669}
21670
21671fn process_completion_for_edit(
21672    completion: &Completion,
21673    intent: CompletionIntent,
21674    buffer: &Entity<Buffer>,
21675    cursor_position: &text::Anchor,
21676    cx: &mut Context<Editor>,
21677) -> CompletionEdit {
21678    let buffer = buffer.read(cx);
21679    let buffer_snapshot = buffer.snapshot();
21680    let (snippet, new_text) = if completion.is_snippet() {
21681        // Workaround for typescript language server issues so that methods don't expand within
21682        // strings and functions with type expressions. The previous point is used because the query
21683        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21684        let mut snippet_source = completion.new_text.clone();
21685        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21686        previous_point.column = previous_point.column.saturating_sub(1);
21687        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21688            && scope.prefers_label_for_snippet_in_completion()
21689            && let Some(label) = completion.label()
21690            && matches!(
21691                completion.kind(),
21692                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21693            )
21694        {
21695            snippet_source = label;
21696        }
21697        match Snippet::parse(&snippet_source).log_err() {
21698            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21699            None => (None, completion.new_text.clone()),
21700        }
21701    } else {
21702        (None, completion.new_text.clone())
21703    };
21704
21705    let mut range_to_replace = {
21706        let replace_range = &completion.replace_range;
21707        if let CompletionSource::Lsp {
21708            insert_range: Some(insert_range),
21709            ..
21710        } = &completion.source
21711        {
21712            debug_assert_eq!(
21713                insert_range.start, replace_range.start,
21714                "insert_range and replace_range should start at the same position"
21715            );
21716            debug_assert!(
21717                insert_range
21718                    .start
21719                    .cmp(cursor_position, &buffer_snapshot)
21720                    .is_le(),
21721                "insert_range should start before or at cursor position"
21722            );
21723            debug_assert!(
21724                replace_range
21725                    .start
21726                    .cmp(cursor_position, &buffer_snapshot)
21727                    .is_le(),
21728                "replace_range should start before or at cursor position"
21729            );
21730
21731            let should_replace = match intent {
21732                CompletionIntent::CompleteWithInsert => false,
21733                CompletionIntent::CompleteWithReplace => true,
21734                CompletionIntent::Complete | CompletionIntent::Compose => {
21735                    let insert_mode =
21736                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21737                            .completions
21738                            .lsp_insert_mode;
21739                    match insert_mode {
21740                        LspInsertMode::Insert => false,
21741                        LspInsertMode::Replace => true,
21742                        LspInsertMode::ReplaceSubsequence => {
21743                            let mut text_to_replace = buffer.chars_for_range(
21744                                buffer.anchor_before(replace_range.start)
21745                                    ..buffer.anchor_after(replace_range.end),
21746                            );
21747                            let mut current_needle = text_to_replace.next();
21748                            for haystack_ch in completion.label.text.chars() {
21749                                if let Some(needle_ch) = current_needle
21750                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21751                                {
21752                                    current_needle = text_to_replace.next();
21753                                }
21754                            }
21755                            current_needle.is_none()
21756                        }
21757                        LspInsertMode::ReplaceSuffix => {
21758                            if replace_range
21759                                .end
21760                                .cmp(cursor_position, &buffer_snapshot)
21761                                .is_gt()
21762                            {
21763                                let range_after_cursor = *cursor_position..replace_range.end;
21764                                let text_after_cursor = buffer
21765                                    .text_for_range(
21766                                        buffer.anchor_before(range_after_cursor.start)
21767                                            ..buffer.anchor_after(range_after_cursor.end),
21768                                    )
21769                                    .collect::<String>()
21770                                    .to_ascii_lowercase();
21771                                completion
21772                                    .label
21773                                    .text
21774                                    .to_ascii_lowercase()
21775                                    .ends_with(&text_after_cursor)
21776                            } else {
21777                                true
21778                            }
21779                        }
21780                    }
21781                }
21782            };
21783
21784            if should_replace {
21785                replace_range.clone()
21786            } else {
21787                insert_range.clone()
21788            }
21789        } else {
21790            replace_range.clone()
21791        }
21792    };
21793
21794    if range_to_replace
21795        .end
21796        .cmp(cursor_position, &buffer_snapshot)
21797        .is_lt()
21798    {
21799        range_to_replace.end = *cursor_position;
21800    }
21801
21802    CompletionEdit {
21803        new_text,
21804        replace_range: range_to_replace.to_offset(buffer),
21805        snippet,
21806    }
21807}
21808
21809struct CompletionEdit {
21810    new_text: String,
21811    replace_range: Range<usize>,
21812    snippet: Option<Snippet>,
21813}
21814
21815fn insert_extra_newline_brackets(
21816    buffer: &MultiBufferSnapshot,
21817    range: Range<usize>,
21818    language: &language::LanguageScope,
21819) -> bool {
21820    let leading_whitespace_len = buffer
21821        .reversed_chars_at(range.start)
21822        .take_while(|c| c.is_whitespace() && *c != '\n')
21823        .map(|c| c.len_utf8())
21824        .sum::<usize>();
21825    let trailing_whitespace_len = buffer
21826        .chars_at(range.end)
21827        .take_while(|c| c.is_whitespace() && *c != '\n')
21828        .map(|c| c.len_utf8())
21829        .sum::<usize>();
21830    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21831
21832    language.brackets().any(|(pair, enabled)| {
21833        let pair_start = pair.start.trim_end();
21834        let pair_end = pair.end.trim_start();
21835
21836        enabled
21837            && pair.newline
21838            && buffer.contains_str_at(range.end, pair_end)
21839            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21840    })
21841}
21842
21843fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21844    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21845        [(buffer, range, _)] => (*buffer, range.clone()),
21846        _ => return false,
21847    };
21848    let pair = {
21849        let mut result: Option<BracketMatch> = None;
21850
21851        for pair in buffer
21852            .all_bracket_ranges(range.clone())
21853            .filter(move |pair| {
21854                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21855            })
21856        {
21857            let len = pair.close_range.end - pair.open_range.start;
21858
21859            if let Some(existing) = &result {
21860                let existing_len = existing.close_range.end - existing.open_range.start;
21861                if len > existing_len {
21862                    continue;
21863                }
21864            }
21865
21866            result = Some(pair);
21867        }
21868
21869        result
21870    };
21871    let Some(pair) = pair else {
21872        return false;
21873    };
21874    pair.newline_only
21875        && buffer
21876            .chars_for_range(pair.open_range.end..range.start)
21877            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21878            .all(|c| c.is_whitespace() && c != '\n')
21879}
21880
21881fn update_uncommitted_diff_for_buffer(
21882    editor: Entity<Editor>,
21883    project: &Entity<Project>,
21884    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21885    buffer: Entity<MultiBuffer>,
21886    cx: &mut App,
21887) -> Task<()> {
21888    let mut tasks = Vec::new();
21889    project.update(cx, |project, cx| {
21890        for buffer in buffers {
21891            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21892                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21893            }
21894        }
21895    });
21896    cx.spawn(async move |cx| {
21897        let diffs = future::join_all(tasks).await;
21898        if editor
21899            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21900            .unwrap_or(false)
21901        {
21902            return;
21903        }
21904
21905        buffer
21906            .update(cx, |buffer, cx| {
21907                for diff in diffs.into_iter().flatten() {
21908                    buffer.add_diff(diff, cx);
21909                }
21910            })
21911            .ok();
21912    })
21913}
21914
21915fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21916    let tab_size = tab_size.get() as usize;
21917    let mut width = offset;
21918
21919    for ch in text.chars() {
21920        width += if ch == '\t' {
21921            tab_size - (width % tab_size)
21922        } else {
21923            1
21924        };
21925    }
21926
21927    width - offset
21928}
21929
21930#[cfg(test)]
21931mod tests {
21932    use super::*;
21933
21934    #[test]
21935    fn test_string_size_with_expanded_tabs() {
21936        let nz = |val| NonZeroU32::new(val).unwrap();
21937        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21938        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21939        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21940        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21941        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21942        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21943        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21944        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21945    }
21946}
21947
21948/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21949struct WordBreakingTokenizer<'a> {
21950    input: &'a str,
21951}
21952
21953impl<'a> WordBreakingTokenizer<'a> {
21954    fn new(input: &'a str) -> Self {
21955        Self { input }
21956    }
21957}
21958
21959fn is_char_ideographic(ch: char) -> bool {
21960    use unicode_script::Script::*;
21961    use unicode_script::UnicodeScript;
21962    matches!(ch.script(), Han | Tangut | Yi)
21963}
21964
21965fn is_grapheme_ideographic(text: &str) -> bool {
21966    text.chars().any(is_char_ideographic)
21967}
21968
21969fn is_grapheme_whitespace(text: &str) -> bool {
21970    text.chars().any(|x| x.is_whitespace())
21971}
21972
21973fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21974    text.chars()
21975        .next()
21976        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
21977}
21978
21979#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21980enum WordBreakToken<'a> {
21981    Word { token: &'a str, grapheme_len: usize },
21982    InlineWhitespace { token: &'a str, grapheme_len: usize },
21983    Newline,
21984}
21985
21986impl<'a> Iterator for WordBreakingTokenizer<'a> {
21987    /// Yields a span, the count of graphemes in the token, and whether it was
21988    /// whitespace. Note that it also breaks at word boundaries.
21989    type Item = WordBreakToken<'a>;
21990
21991    fn next(&mut self) -> Option<Self::Item> {
21992        use unicode_segmentation::UnicodeSegmentation;
21993        if self.input.is_empty() {
21994            return None;
21995        }
21996
21997        let mut iter = self.input.graphemes(true).peekable();
21998        let mut offset = 0;
21999        let mut grapheme_len = 0;
22000        if let Some(first_grapheme) = iter.next() {
22001            let is_newline = first_grapheme == "\n";
22002            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22003            offset += first_grapheme.len();
22004            grapheme_len += 1;
22005            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22006                if let Some(grapheme) = iter.peek().copied()
22007                    && should_stay_with_preceding_ideograph(grapheme)
22008                {
22009                    offset += grapheme.len();
22010                    grapheme_len += 1;
22011                }
22012            } else {
22013                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22014                let mut next_word_bound = words.peek().copied();
22015                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22016                    next_word_bound = words.next();
22017                }
22018                while let Some(grapheme) = iter.peek().copied() {
22019                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22020                        break;
22021                    };
22022                    if is_grapheme_whitespace(grapheme) != is_whitespace
22023                        || (grapheme == "\n") != is_newline
22024                    {
22025                        break;
22026                    };
22027                    offset += grapheme.len();
22028                    grapheme_len += 1;
22029                    iter.next();
22030                }
22031            }
22032            let token = &self.input[..offset];
22033            self.input = &self.input[offset..];
22034            if token == "\n" {
22035                Some(WordBreakToken::Newline)
22036            } else if is_whitespace {
22037                Some(WordBreakToken::InlineWhitespace {
22038                    token,
22039                    grapheme_len,
22040                })
22041            } else {
22042                Some(WordBreakToken::Word {
22043                    token,
22044                    grapheme_len,
22045                })
22046            }
22047        } else {
22048            None
22049        }
22050    }
22051}
22052
22053#[test]
22054fn test_word_breaking_tokenizer() {
22055    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22056        ("", &[]),
22057        ("  ", &[whitespace("  ", 2)]),
22058        ("Ʒ", &[word("Ʒ", 1)]),
22059        ("Ǽ", &[word("Ǽ", 1)]),
22060        ("", &[word("", 1)]),
22061        ("⋑⋑", &[word("⋑⋑", 2)]),
22062        (
22063            "原理,进而",
22064            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22065        ),
22066        (
22067            "hello world",
22068            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22069        ),
22070        (
22071            "hello, world",
22072            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22073        ),
22074        (
22075            "  hello world",
22076            &[
22077                whitespace("  ", 2),
22078                word("hello", 5),
22079                whitespace(" ", 1),
22080                word("world", 5),
22081            ],
22082        ),
22083        (
22084            "这是什么 \n 钢笔",
22085            &[
22086                word("", 1),
22087                word("", 1),
22088                word("", 1),
22089                word("", 1),
22090                whitespace(" ", 1),
22091                newline(),
22092                whitespace(" ", 1),
22093                word("", 1),
22094                word("", 1),
22095            ],
22096        ),
22097        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22098    ];
22099
22100    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22101        WordBreakToken::Word {
22102            token,
22103            grapheme_len,
22104        }
22105    }
22106
22107    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22108        WordBreakToken::InlineWhitespace {
22109            token,
22110            grapheme_len,
22111        }
22112    }
22113
22114    fn newline() -> WordBreakToken<'static> {
22115        WordBreakToken::Newline
22116    }
22117
22118    for (input, result) in tests {
22119        assert_eq!(
22120            WordBreakingTokenizer::new(input)
22121                .collect::<Vec<_>>()
22122                .as_slice(),
22123            *result,
22124        );
22125    }
22126}
22127
22128fn wrap_with_prefix(
22129    first_line_prefix: String,
22130    subsequent_lines_prefix: String,
22131    unwrapped_text: String,
22132    wrap_column: usize,
22133    tab_size: NonZeroU32,
22134    preserve_existing_whitespace: bool,
22135) -> String {
22136    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22137    let subsequent_lines_prefix_len =
22138        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22139    let mut wrapped_text = String::new();
22140    let mut current_line = first_line_prefix;
22141    let mut is_first_line = true;
22142
22143    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22144    let mut current_line_len = first_line_prefix_len;
22145    let mut in_whitespace = false;
22146    for token in tokenizer {
22147        let have_preceding_whitespace = in_whitespace;
22148        match token {
22149            WordBreakToken::Word {
22150                token,
22151                grapheme_len,
22152            } => {
22153                in_whitespace = false;
22154                let current_prefix_len = if is_first_line {
22155                    first_line_prefix_len
22156                } else {
22157                    subsequent_lines_prefix_len
22158                };
22159                if current_line_len + grapheme_len > wrap_column
22160                    && current_line_len != current_prefix_len
22161                {
22162                    wrapped_text.push_str(current_line.trim_end());
22163                    wrapped_text.push('\n');
22164                    is_first_line = false;
22165                    current_line = subsequent_lines_prefix.clone();
22166                    current_line_len = subsequent_lines_prefix_len;
22167                }
22168                current_line.push_str(token);
22169                current_line_len += grapheme_len;
22170            }
22171            WordBreakToken::InlineWhitespace {
22172                mut token,
22173                mut grapheme_len,
22174            } => {
22175                in_whitespace = true;
22176                if have_preceding_whitespace && !preserve_existing_whitespace {
22177                    continue;
22178                }
22179                if !preserve_existing_whitespace {
22180                    token = " ";
22181                    grapheme_len = 1;
22182                }
22183                let current_prefix_len = if is_first_line {
22184                    first_line_prefix_len
22185                } else {
22186                    subsequent_lines_prefix_len
22187                };
22188                if current_line_len + grapheme_len > wrap_column {
22189                    wrapped_text.push_str(current_line.trim_end());
22190                    wrapped_text.push('\n');
22191                    is_first_line = false;
22192                    current_line = subsequent_lines_prefix.clone();
22193                    current_line_len = subsequent_lines_prefix_len;
22194                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22195                    current_line.push_str(token);
22196                    current_line_len += grapheme_len;
22197                }
22198            }
22199            WordBreakToken::Newline => {
22200                in_whitespace = true;
22201                let current_prefix_len = if is_first_line {
22202                    first_line_prefix_len
22203                } else {
22204                    subsequent_lines_prefix_len
22205                };
22206                if preserve_existing_whitespace {
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 have_preceding_whitespace {
22213                    continue;
22214                } else if current_line_len + 1 > wrap_column
22215                    && current_line_len != current_prefix_len
22216                {
22217                    wrapped_text.push_str(current_line.trim_end());
22218                    wrapped_text.push('\n');
22219                    is_first_line = false;
22220                    current_line = subsequent_lines_prefix.clone();
22221                    current_line_len = subsequent_lines_prefix_len;
22222                } else if current_line_len != current_prefix_len {
22223                    current_line.push(' ');
22224                    current_line_len += 1;
22225                }
22226            }
22227        }
22228    }
22229
22230    if !current_line.is_empty() {
22231        wrapped_text.push_str(&current_line);
22232    }
22233    wrapped_text
22234}
22235
22236#[test]
22237fn test_wrap_with_prefix() {
22238    assert_eq!(
22239        wrap_with_prefix(
22240            "# ".to_string(),
22241            "# ".to_string(),
22242            "abcdefg".to_string(),
22243            4,
22244            NonZeroU32::new(4).unwrap(),
22245            false,
22246        ),
22247        "# abcdefg"
22248    );
22249    assert_eq!(
22250        wrap_with_prefix(
22251            "".to_string(),
22252            "".to_string(),
22253            "\thello world".to_string(),
22254            8,
22255            NonZeroU32::new(4).unwrap(),
22256            false,
22257        ),
22258        "hello\nworld"
22259    );
22260    assert_eq!(
22261        wrap_with_prefix(
22262            "// ".to_string(),
22263            "// ".to_string(),
22264            "xx \nyy zz aa bb cc".to_string(),
22265            12,
22266            NonZeroU32::new(4).unwrap(),
22267            false,
22268        ),
22269        "// xx yy zz\n// aa bb cc"
22270    );
22271    assert_eq!(
22272        wrap_with_prefix(
22273            String::new(),
22274            String::new(),
22275            "这是什么 \n 钢笔".to_string(),
22276            3,
22277            NonZeroU32::new(4).unwrap(),
22278            false,
22279        ),
22280        "这是什\n么 钢\n"
22281    );
22282}
22283
22284pub trait CollaborationHub {
22285    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22286    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22287    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22288}
22289
22290impl CollaborationHub for Entity<Project> {
22291    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22292        self.read(cx).collaborators()
22293    }
22294
22295    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22296        self.read(cx).user_store().read(cx).participant_indices()
22297    }
22298
22299    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22300        let this = self.read(cx);
22301        let user_ids = this.collaborators().values().map(|c| c.user_id);
22302        this.user_store().read(cx).participant_names(user_ids, cx)
22303    }
22304}
22305
22306pub trait SemanticsProvider {
22307    fn hover(
22308        &self,
22309        buffer: &Entity<Buffer>,
22310        position: text::Anchor,
22311        cx: &mut App,
22312    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22313
22314    fn inline_values(
22315        &self,
22316        buffer_handle: Entity<Buffer>,
22317        range: Range<text::Anchor>,
22318        cx: &mut App,
22319    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22320
22321    fn inlay_hints(
22322        &self,
22323        buffer_handle: Entity<Buffer>,
22324        range: Range<text::Anchor>,
22325        cx: &mut App,
22326    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22327
22328    fn resolve_inlay_hint(
22329        &self,
22330        hint: InlayHint,
22331        buffer_handle: Entity<Buffer>,
22332        server_id: LanguageServerId,
22333        cx: &mut App,
22334    ) -> Option<Task<anyhow::Result<InlayHint>>>;
22335
22336    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22337
22338    fn document_highlights(
22339        &self,
22340        buffer: &Entity<Buffer>,
22341        position: text::Anchor,
22342        cx: &mut App,
22343    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22344
22345    fn definitions(
22346        &self,
22347        buffer: &Entity<Buffer>,
22348        position: text::Anchor,
22349        kind: GotoDefinitionKind,
22350        cx: &mut App,
22351    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22352
22353    fn range_for_rename(
22354        &self,
22355        buffer: &Entity<Buffer>,
22356        position: text::Anchor,
22357        cx: &mut App,
22358    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22359
22360    fn perform_rename(
22361        &self,
22362        buffer: &Entity<Buffer>,
22363        position: text::Anchor,
22364        new_name: String,
22365        cx: &mut App,
22366    ) -> Option<Task<Result<ProjectTransaction>>>;
22367}
22368
22369pub trait CompletionProvider {
22370    fn completions(
22371        &self,
22372        excerpt_id: ExcerptId,
22373        buffer: &Entity<Buffer>,
22374        buffer_position: text::Anchor,
22375        trigger: CompletionContext,
22376        window: &mut Window,
22377        cx: &mut Context<Editor>,
22378    ) -> Task<Result<Vec<CompletionResponse>>>;
22379
22380    fn resolve_completions(
22381        &self,
22382        _buffer: Entity<Buffer>,
22383        _completion_indices: Vec<usize>,
22384        _completions: Rc<RefCell<Box<[Completion]>>>,
22385        _cx: &mut Context<Editor>,
22386    ) -> Task<Result<bool>> {
22387        Task::ready(Ok(false))
22388    }
22389
22390    fn apply_additional_edits_for_completion(
22391        &self,
22392        _buffer: Entity<Buffer>,
22393        _completions: Rc<RefCell<Box<[Completion]>>>,
22394        _completion_index: usize,
22395        _push_to_history: bool,
22396        _cx: &mut Context<Editor>,
22397    ) -> Task<Result<Option<language::Transaction>>> {
22398        Task::ready(Ok(None))
22399    }
22400
22401    fn is_completion_trigger(
22402        &self,
22403        buffer: &Entity<Buffer>,
22404        position: language::Anchor,
22405        text: &str,
22406        trigger_in_words: bool,
22407        menu_is_open: bool,
22408        cx: &mut Context<Editor>,
22409    ) -> bool;
22410
22411    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22412
22413    fn sort_completions(&self) -> bool {
22414        true
22415    }
22416
22417    fn filter_completions(&self) -> bool {
22418        true
22419    }
22420}
22421
22422pub trait CodeActionProvider {
22423    fn id(&self) -> Arc<str>;
22424
22425    fn code_actions(
22426        &self,
22427        buffer: &Entity<Buffer>,
22428        range: Range<text::Anchor>,
22429        window: &mut Window,
22430        cx: &mut App,
22431    ) -> Task<Result<Vec<CodeAction>>>;
22432
22433    fn apply_code_action(
22434        &self,
22435        buffer_handle: Entity<Buffer>,
22436        action: CodeAction,
22437        excerpt_id: ExcerptId,
22438        push_to_history: bool,
22439        window: &mut Window,
22440        cx: &mut App,
22441    ) -> Task<Result<ProjectTransaction>>;
22442}
22443
22444impl CodeActionProvider for Entity<Project> {
22445    fn id(&self) -> Arc<str> {
22446        "project".into()
22447    }
22448
22449    fn code_actions(
22450        &self,
22451        buffer: &Entity<Buffer>,
22452        range: Range<text::Anchor>,
22453        _window: &mut Window,
22454        cx: &mut App,
22455    ) -> Task<Result<Vec<CodeAction>>> {
22456        self.update(cx, |project, cx| {
22457            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22458            let code_actions = project.code_actions(buffer, range, None, cx);
22459            cx.background_spawn(async move {
22460                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22461                Ok(code_lens_actions
22462                    .context("code lens fetch")?
22463                    .into_iter()
22464                    .flatten()
22465                    .chain(
22466                        code_actions
22467                            .context("code action fetch")?
22468                            .into_iter()
22469                            .flatten(),
22470                    )
22471                    .collect())
22472            })
22473        })
22474    }
22475
22476    fn apply_code_action(
22477        &self,
22478        buffer_handle: Entity<Buffer>,
22479        action: CodeAction,
22480        _excerpt_id: ExcerptId,
22481        push_to_history: bool,
22482        _window: &mut Window,
22483        cx: &mut App,
22484    ) -> Task<Result<ProjectTransaction>> {
22485        self.update(cx, |project, cx| {
22486            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22487        })
22488    }
22489}
22490
22491fn snippet_completions(
22492    project: &Project,
22493    buffer: &Entity<Buffer>,
22494    buffer_position: text::Anchor,
22495    cx: &mut App,
22496) -> Task<Result<CompletionResponse>> {
22497    let languages = buffer.read(cx).languages_at(buffer_position);
22498    let snippet_store = project.snippets().read(cx);
22499
22500    let scopes: Vec<_> = languages
22501        .iter()
22502        .filter_map(|language| {
22503            let language_name = language.lsp_id();
22504            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22505
22506            if snippets.is_empty() {
22507                None
22508            } else {
22509                Some((language.default_scope(), snippets))
22510            }
22511        })
22512        .collect();
22513
22514    if scopes.is_empty() {
22515        return Task::ready(Ok(CompletionResponse {
22516            completions: vec![],
22517            display_options: CompletionDisplayOptions::default(),
22518            is_incomplete: false,
22519        }));
22520    }
22521
22522    let snapshot = buffer.read(cx).text_snapshot();
22523    let chars: String = snapshot
22524        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22525        .collect();
22526    let executor = cx.background_executor().clone();
22527
22528    cx.background_spawn(async move {
22529        let mut is_incomplete = false;
22530        let mut completions: Vec<Completion> = Vec::new();
22531        for (scope, snippets) in scopes.into_iter() {
22532            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22533            let mut last_word = chars
22534                .chars()
22535                .take_while(|c| classifier.is_word(*c))
22536                .collect::<String>();
22537            last_word = last_word.chars().rev().collect();
22538
22539            if last_word.is_empty() {
22540                return Ok(CompletionResponse {
22541                    completions: vec![],
22542                    display_options: CompletionDisplayOptions::default(),
22543                    is_incomplete: true,
22544                });
22545            }
22546
22547            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22548            let to_lsp = |point: &text::Anchor| {
22549                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22550                point_to_lsp(end)
22551            };
22552            let lsp_end = to_lsp(&buffer_position);
22553
22554            let candidates = snippets
22555                .iter()
22556                .enumerate()
22557                .flat_map(|(ix, snippet)| {
22558                    snippet
22559                        .prefix
22560                        .iter()
22561                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22562                })
22563                .collect::<Vec<StringMatchCandidate>>();
22564
22565            const MAX_RESULTS: usize = 100;
22566            let mut matches = fuzzy::match_strings(
22567                &candidates,
22568                &last_word,
22569                last_word.chars().any(|c| c.is_uppercase()),
22570                true,
22571                MAX_RESULTS,
22572                &Default::default(),
22573                executor.clone(),
22574            )
22575            .await;
22576
22577            if matches.len() >= MAX_RESULTS {
22578                is_incomplete = true;
22579            }
22580
22581            // Remove all candidates where the query's start does not match the start of any word in the candidate
22582            if let Some(query_start) = last_word.chars().next() {
22583                matches.retain(|string_match| {
22584                    split_words(&string_match.string).any(|word| {
22585                        // Check that the first codepoint of the word as lowercase matches the first
22586                        // codepoint of the query as lowercase
22587                        word.chars()
22588                            .flat_map(|codepoint| codepoint.to_lowercase())
22589                            .zip(query_start.to_lowercase())
22590                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22591                    })
22592                });
22593            }
22594
22595            let matched_strings = matches
22596                .into_iter()
22597                .map(|m| m.string)
22598                .collect::<HashSet<_>>();
22599
22600            completions.extend(snippets.iter().filter_map(|snippet| {
22601                let matching_prefix = snippet
22602                    .prefix
22603                    .iter()
22604                    .find(|prefix| matched_strings.contains(*prefix))?;
22605                let start = as_offset - last_word.len();
22606                let start = snapshot.anchor_before(start);
22607                let range = start..buffer_position;
22608                let lsp_start = to_lsp(&start);
22609                let lsp_range = lsp::Range {
22610                    start: lsp_start,
22611                    end: lsp_end,
22612                };
22613                Some(Completion {
22614                    replace_range: range,
22615                    new_text: snippet.body.clone(),
22616                    source: CompletionSource::Lsp {
22617                        insert_range: None,
22618                        server_id: LanguageServerId(usize::MAX),
22619                        resolved: true,
22620                        lsp_completion: Box::new(lsp::CompletionItem {
22621                            label: snippet.prefix.first().unwrap().clone(),
22622                            kind: Some(CompletionItemKind::SNIPPET),
22623                            label_details: snippet.description.as_ref().map(|description| {
22624                                lsp::CompletionItemLabelDetails {
22625                                    detail: Some(description.clone()),
22626                                    description: None,
22627                                }
22628                            }),
22629                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22630                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22631                                lsp::InsertReplaceEdit {
22632                                    new_text: snippet.body.clone(),
22633                                    insert: lsp_range,
22634                                    replace: lsp_range,
22635                                },
22636                            )),
22637                            filter_text: Some(snippet.body.clone()),
22638                            sort_text: Some(char::MAX.to_string()),
22639                            ..lsp::CompletionItem::default()
22640                        }),
22641                        lsp_defaults: None,
22642                    },
22643                    label: CodeLabel {
22644                        text: matching_prefix.clone(),
22645                        runs: Vec::new(),
22646                        filter_range: 0..matching_prefix.len(),
22647                    },
22648                    icon_path: None,
22649                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22650                        single_line: snippet.name.clone().into(),
22651                        plain_text: snippet
22652                            .description
22653                            .clone()
22654                            .map(|description| description.into()),
22655                    }),
22656                    insert_text_mode: None,
22657                    confirm: None,
22658                })
22659            }))
22660        }
22661
22662        Ok(CompletionResponse {
22663            completions,
22664            display_options: CompletionDisplayOptions::default(),
22665            is_incomplete,
22666        })
22667    })
22668}
22669
22670impl CompletionProvider for Entity<Project> {
22671    fn completions(
22672        &self,
22673        _excerpt_id: ExcerptId,
22674        buffer: &Entity<Buffer>,
22675        buffer_position: text::Anchor,
22676        options: CompletionContext,
22677        _window: &mut Window,
22678        cx: &mut Context<Editor>,
22679    ) -> Task<Result<Vec<CompletionResponse>>> {
22680        self.update(cx, |project, cx| {
22681            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22682            let project_completions = project.completions(buffer, buffer_position, options, cx);
22683            cx.background_spawn(async move {
22684                let mut responses = project_completions.await?;
22685                let snippets = snippets.await?;
22686                if !snippets.completions.is_empty() {
22687                    responses.push(snippets);
22688                }
22689                Ok(responses)
22690            })
22691        })
22692    }
22693
22694    fn resolve_completions(
22695        &self,
22696        buffer: Entity<Buffer>,
22697        completion_indices: Vec<usize>,
22698        completions: Rc<RefCell<Box<[Completion]>>>,
22699        cx: &mut Context<Editor>,
22700    ) -> Task<Result<bool>> {
22701        self.update(cx, |project, cx| {
22702            project.lsp_store().update(cx, |lsp_store, cx| {
22703                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22704            })
22705        })
22706    }
22707
22708    fn apply_additional_edits_for_completion(
22709        &self,
22710        buffer: Entity<Buffer>,
22711        completions: Rc<RefCell<Box<[Completion]>>>,
22712        completion_index: usize,
22713        push_to_history: bool,
22714        cx: &mut Context<Editor>,
22715    ) -> Task<Result<Option<language::Transaction>>> {
22716        self.update(cx, |project, cx| {
22717            project.lsp_store().update(cx, |lsp_store, cx| {
22718                lsp_store.apply_additional_edits_for_completion(
22719                    buffer,
22720                    completions,
22721                    completion_index,
22722                    push_to_history,
22723                    cx,
22724                )
22725            })
22726        })
22727    }
22728
22729    fn is_completion_trigger(
22730        &self,
22731        buffer: &Entity<Buffer>,
22732        position: language::Anchor,
22733        text: &str,
22734        trigger_in_words: bool,
22735        menu_is_open: bool,
22736        cx: &mut Context<Editor>,
22737    ) -> bool {
22738        let mut chars = text.chars();
22739        let char = if let Some(char) = chars.next() {
22740            char
22741        } else {
22742            return false;
22743        };
22744        if chars.next().is_some() {
22745            return false;
22746        }
22747
22748        let buffer = buffer.read(cx);
22749        let snapshot = buffer.snapshot();
22750        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22751            return false;
22752        }
22753        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22754        if trigger_in_words && classifier.is_word(char) {
22755            return true;
22756        }
22757
22758        buffer.completion_triggers().contains(text)
22759    }
22760}
22761
22762impl SemanticsProvider for Entity<Project> {
22763    fn hover(
22764        &self,
22765        buffer: &Entity<Buffer>,
22766        position: text::Anchor,
22767        cx: &mut App,
22768    ) -> Option<Task<Option<Vec<project::Hover>>>> {
22769        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22770    }
22771
22772    fn document_highlights(
22773        &self,
22774        buffer: &Entity<Buffer>,
22775        position: text::Anchor,
22776        cx: &mut App,
22777    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22778        Some(self.update(cx, |project, cx| {
22779            project.document_highlights(buffer, position, cx)
22780        }))
22781    }
22782
22783    fn definitions(
22784        &self,
22785        buffer: &Entity<Buffer>,
22786        position: text::Anchor,
22787        kind: GotoDefinitionKind,
22788        cx: &mut App,
22789    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
22790        Some(self.update(cx, |project, cx| match kind {
22791            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22792            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22793            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22794            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22795        }))
22796    }
22797
22798    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22799        self.update(cx, |project, cx| {
22800            if project
22801                .active_debug_session(cx)
22802                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22803            {
22804                return true;
22805            }
22806
22807            buffer.update(cx, |buffer, cx| {
22808                project.any_language_server_supports_inlay_hints(buffer, cx)
22809            })
22810        })
22811    }
22812
22813    fn inline_values(
22814        &self,
22815        buffer_handle: Entity<Buffer>,
22816        range: Range<text::Anchor>,
22817        cx: &mut App,
22818    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22819        self.update(cx, |project, cx| {
22820            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22821
22822            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22823        })
22824    }
22825
22826    fn inlay_hints(
22827        &self,
22828        buffer_handle: Entity<Buffer>,
22829        range: Range<text::Anchor>,
22830        cx: &mut App,
22831    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22832        Some(self.update(cx, |project, cx| {
22833            project.inlay_hints(buffer_handle, range, cx)
22834        }))
22835    }
22836
22837    fn resolve_inlay_hint(
22838        &self,
22839        hint: InlayHint,
22840        buffer_handle: Entity<Buffer>,
22841        server_id: LanguageServerId,
22842        cx: &mut App,
22843    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22844        Some(self.update(cx, |project, cx| {
22845            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22846        }))
22847    }
22848
22849    fn range_for_rename(
22850        &self,
22851        buffer: &Entity<Buffer>,
22852        position: text::Anchor,
22853        cx: &mut App,
22854    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22855        Some(self.update(cx, |project, cx| {
22856            let buffer = buffer.clone();
22857            let task = project.prepare_rename(buffer.clone(), position, cx);
22858            cx.spawn(async move |_, cx| {
22859                Ok(match task.await? {
22860                    PrepareRenameResponse::Success(range) => Some(range),
22861                    PrepareRenameResponse::InvalidPosition => None,
22862                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22863                        // Fallback on using TreeSitter info to determine identifier range
22864                        buffer.read_with(cx, |buffer, _| {
22865                            let snapshot = buffer.snapshot();
22866                            let (range, kind) = snapshot.surrounding_word(position, false);
22867                            if kind != Some(CharKind::Word) {
22868                                return None;
22869                            }
22870                            Some(
22871                                snapshot.anchor_before(range.start)
22872                                    ..snapshot.anchor_after(range.end),
22873                            )
22874                        })?
22875                    }
22876                })
22877            })
22878        }))
22879    }
22880
22881    fn perform_rename(
22882        &self,
22883        buffer: &Entity<Buffer>,
22884        position: text::Anchor,
22885        new_name: String,
22886        cx: &mut App,
22887    ) -> Option<Task<Result<ProjectTransaction>>> {
22888        Some(self.update(cx, |project, cx| {
22889            project.perform_rename(buffer.clone(), position, new_name, cx)
22890        }))
22891    }
22892}
22893
22894fn inlay_hint_settings(
22895    location: Anchor,
22896    snapshot: &MultiBufferSnapshot,
22897    cx: &mut Context<Editor>,
22898) -> InlayHintSettings {
22899    let file = snapshot.file_at(location);
22900    let language = snapshot.language_at(location).map(|l| l.name());
22901    language_settings(language, file, cx).inlay_hints
22902}
22903
22904fn consume_contiguous_rows(
22905    contiguous_row_selections: &mut Vec<Selection<Point>>,
22906    selection: &Selection<Point>,
22907    display_map: &DisplaySnapshot,
22908    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22909) -> (MultiBufferRow, MultiBufferRow) {
22910    contiguous_row_selections.push(selection.clone());
22911    let start_row = starting_row(selection, display_map);
22912    let mut end_row = ending_row(selection, display_map);
22913
22914    while let Some(next_selection) = selections.peek() {
22915        if next_selection.start.row <= end_row.0 {
22916            end_row = ending_row(next_selection, display_map);
22917            contiguous_row_selections.push(selections.next().unwrap().clone());
22918        } else {
22919            break;
22920        }
22921    }
22922    (start_row, end_row)
22923}
22924
22925fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22926    if selection.start.column > 0 {
22927        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22928    } else {
22929        MultiBufferRow(selection.start.row)
22930    }
22931}
22932
22933fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22934    if next_selection.end.column > 0 || next_selection.is_empty() {
22935        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22936    } else {
22937        MultiBufferRow(next_selection.end.row)
22938    }
22939}
22940
22941impl EditorSnapshot {
22942    pub fn remote_selections_in_range<'a>(
22943        &'a self,
22944        range: &'a Range<Anchor>,
22945        collaboration_hub: &dyn CollaborationHub,
22946        cx: &'a App,
22947    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22948        let participant_names = collaboration_hub.user_names(cx);
22949        let participant_indices = collaboration_hub.user_participant_indices(cx);
22950        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22951        let collaborators_by_replica_id = collaborators_by_peer_id
22952            .values()
22953            .map(|collaborator| (collaborator.replica_id, collaborator))
22954            .collect::<HashMap<_, _>>();
22955        self.buffer_snapshot
22956            .selections_in_range(range, false)
22957            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22958                if replica_id == AGENT_REPLICA_ID {
22959                    Some(RemoteSelection {
22960                        replica_id,
22961                        selection,
22962                        cursor_shape,
22963                        line_mode,
22964                        collaborator_id: CollaboratorId::Agent,
22965                        user_name: Some("Agent".into()),
22966                        color: cx.theme().players().agent(),
22967                    })
22968                } else {
22969                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22970                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22971                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22972                    Some(RemoteSelection {
22973                        replica_id,
22974                        selection,
22975                        cursor_shape,
22976                        line_mode,
22977                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22978                        user_name,
22979                        color: if let Some(index) = participant_index {
22980                            cx.theme().players().color_for_participant(index.0)
22981                        } else {
22982                            cx.theme().players().absent()
22983                        },
22984                    })
22985                }
22986            })
22987    }
22988
22989    pub fn hunks_for_ranges(
22990        &self,
22991        ranges: impl IntoIterator<Item = Range<Point>>,
22992    ) -> Vec<MultiBufferDiffHunk> {
22993        let mut hunks = Vec::new();
22994        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22995            HashMap::default();
22996        for query_range in ranges {
22997            let query_rows =
22998                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22999            for hunk in self.buffer_snapshot.diff_hunks_in_range(
23000                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23001            ) {
23002                // Include deleted hunks that are adjacent to the query range, because
23003                // otherwise they would be missed.
23004                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23005                if hunk.status().is_deleted() {
23006                    intersects_range |= hunk.row_range.start == query_rows.end;
23007                    intersects_range |= hunk.row_range.end == query_rows.start;
23008                }
23009                if intersects_range {
23010                    if !processed_buffer_rows
23011                        .entry(hunk.buffer_id)
23012                        .or_default()
23013                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23014                    {
23015                        continue;
23016                    }
23017                    hunks.push(hunk);
23018                }
23019            }
23020        }
23021
23022        hunks
23023    }
23024
23025    fn display_diff_hunks_for_rows<'a>(
23026        &'a self,
23027        display_rows: Range<DisplayRow>,
23028        folded_buffers: &'a HashSet<BufferId>,
23029    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23030        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23031        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23032
23033        self.buffer_snapshot
23034            .diff_hunks_in_range(buffer_start..buffer_end)
23035            .filter_map(|hunk| {
23036                if folded_buffers.contains(&hunk.buffer_id) {
23037                    return None;
23038                }
23039
23040                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23041                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23042
23043                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23044                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23045
23046                let display_hunk = if hunk_display_start.column() != 0 {
23047                    DisplayDiffHunk::Folded {
23048                        display_row: hunk_display_start.row(),
23049                    }
23050                } else {
23051                    let mut end_row = hunk_display_end.row();
23052                    if hunk_display_end.column() > 0 {
23053                        end_row.0 += 1;
23054                    }
23055                    let is_created_file = hunk.is_created_file();
23056                    DisplayDiffHunk::Unfolded {
23057                        status: hunk.status(),
23058                        diff_base_byte_range: hunk.diff_base_byte_range,
23059                        display_row_range: hunk_display_start.row()..end_row,
23060                        multi_buffer_range: Anchor::range_in_buffer(
23061                            hunk.excerpt_id,
23062                            hunk.buffer_id,
23063                            hunk.buffer_range,
23064                        ),
23065                        is_created_file,
23066                    }
23067                };
23068
23069                Some(display_hunk)
23070            })
23071    }
23072
23073    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23074        self.display_snapshot.buffer_snapshot.language_at(position)
23075    }
23076
23077    pub fn is_focused(&self) -> bool {
23078        self.is_focused
23079    }
23080
23081    pub fn placeholder_text(&self) -> Option<String> {
23082        self.placeholder_display_snapshot
23083            .as_ref()
23084            .map(|display_map| display_map.text())
23085    }
23086
23087    pub fn scroll_position(&self) -> gpui::Point<f32> {
23088        self.scroll_anchor.scroll_position(&self.display_snapshot)
23089    }
23090
23091    fn gutter_dimensions(
23092        &self,
23093        font_id: FontId,
23094        font_size: Pixels,
23095        max_line_number_width: Pixels,
23096        cx: &App,
23097    ) -> Option<GutterDimensions> {
23098        if !self.show_gutter {
23099            return None;
23100        }
23101
23102        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23103        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23104
23105        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23106            matches!(
23107                ProjectSettings::get_global(cx).git.git_gutter,
23108                Some(GitGutterSetting::TrackedFiles)
23109            )
23110        });
23111        let gutter_settings = EditorSettings::get_global(cx).gutter;
23112        let show_line_numbers = self
23113            .show_line_numbers
23114            .unwrap_or(gutter_settings.line_numbers);
23115        let line_gutter_width = if show_line_numbers {
23116            // Avoid flicker-like gutter resizes when the line number gains another digit by
23117            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23118            let min_width_for_number_on_gutter =
23119                ch_advance * gutter_settings.min_line_number_digits as f32;
23120            max_line_number_width.max(min_width_for_number_on_gutter)
23121        } else {
23122            0.0.into()
23123        };
23124
23125        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23126        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23127
23128        let git_blame_entries_width =
23129            self.git_blame_gutter_max_author_length
23130                .map(|max_author_length| {
23131                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23132                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23133
23134                    /// The number of characters to dedicate to gaps and margins.
23135                    const SPACING_WIDTH: usize = 4;
23136
23137                    let max_char_count = max_author_length.min(renderer.max_author_length())
23138                        + ::git::SHORT_SHA_LENGTH
23139                        + MAX_RELATIVE_TIMESTAMP.len()
23140                        + SPACING_WIDTH;
23141
23142                    ch_advance * max_char_count
23143                });
23144
23145        let is_singleton = self.buffer_snapshot.is_singleton();
23146
23147        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23148        left_padding += if !is_singleton {
23149            ch_width * 4.0
23150        } else if show_runnables || show_breakpoints {
23151            ch_width * 3.0
23152        } else if show_git_gutter && show_line_numbers {
23153            ch_width * 2.0
23154        } else if show_git_gutter || show_line_numbers {
23155            ch_width
23156        } else {
23157            px(0.)
23158        };
23159
23160        let shows_folds = is_singleton && gutter_settings.folds;
23161
23162        let right_padding = if shows_folds && show_line_numbers {
23163            ch_width * 4.0
23164        } else if shows_folds || (!is_singleton && show_line_numbers) {
23165            ch_width * 3.0
23166        } else if show_line_numbers {
23167            ch_width
23168        } else {
23169            px(0.)
23170        };
23171
23172        Some(GutterDimensions {
23173            left_padding,
23174            right_padding,
23175            width: line_gutter_width + left_padding + right_padding,
23176            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23177            git_blame_entries_width,
23178        })
23179    }
23180
23181    pub fn render_crease_toggle(
23182        &self,
23183        buffer_row: MultiBufferRow,
23184        row_contains_cursor: bool,
23185        editor: Entity<Editor>,
23186        window: &mut Window,
23187        cx: &mut App,
23188    ) -> Option<AnyElement> {
23189        let folded = self.is_line_folded(buffer_row);
23190        let mut is_foldable = false;
23191
23192        if let Some(crease) = self
23193            .crease_snapshot
23194            .query_row(buffer_row, &self.buffer_snapshot)
23195        {
23196            is_foldable = true;
23197            match crease {
23198                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23199                    if let Some(render_toggle) = render_toggle {
23200                        let toggle_callback =
23201                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23202                                if folded {
23203                                    editor.update(cx, |editor, cx| {
23204                                        editor.fold_at(buffer_row, window, cx)
23205                                    });
23206                                } else {
23207                                    editor.update(cx, |editor, cx| {
23208                                        editor.unfold_at(buffer_row, window, cx)
23209                                    });
23210                                }
23211                            });
23212                        return Some((render_toggle)(
23213                            buffer_row,
23214                            folded,
23215                            toggle_callback,
23216                            window,
23217                            cx,
23218                        ));
23219                    }
23220                }
23221            }
23222        }
23223
23224        is_foldable |= self.starts_indent(buffer_row);
23225
23226        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23227            Some(
23228                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23229                    .toggle_state(folded)
23230                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23231                        if folded {
23232                            this.unfold_at(buffer_row, window, cx);
23233                        } else {
23234                            this.fold_at(buffer_row, window, cx);
23235                        }
23236                    }))
23237                    .into_any_element(),
23238            )
23239        } else {
23240            None
23241        }
23242    }
23243
23244    pub fn render_crease_trailer(
23245        &self,
23246        buffer_row: MultiBufferRow,
23247        window: &mut Window,
23248        cx: &mut App,
23249    ) -> Option<AnyElement> {
23250        let folded = self.is_line_folded(buffer_row);
23251        if let Crease::Inline { render_trailer, .. } = self
23252            .crease_snapshot
23253            .query_row(buffer_row, &self.buffer_snapshot)?
23254        {
23255            let render_trailer = render_trailer.as_ref()?;
23256            Some(render_trailer(buffer_row, folded, window, cx))
23257        } else {
23258            None
23259        }
23260    }
23261}
23262
23263impl Deref for EditorSnapshot {
23264    type Target = DisplaySnapshot;
23265
23266    fn deref(&self) -> &Self::Target {
23267        &self.display_snapshot
23268    }
23269}
23270
23271#[derive(Clone, Debug, PartialEq, Eq)]
23272pub enum EditorEvent {
23273    InputIgnored {
23274        text: Arc<str>,
23275    },
23276    InputHandled {
23277        utf16_range_to_replace: Option<Range<isize>>,
23278        text: Arc<str>,
23279    },
23280    ExcerptsAdded {
23281        buffer: Entity<Buffer>,
23282        predecessor: ExcerptId,
23283        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23284    },
23285    ExcerptsRemoved {
23286        ids: Vec<ExcerptId>,
23287        removed_buffer_ids: Vec<BufferId>,
23288    },
23289    BufferFoldToggled {
23290        ids: Vec<ExcerptId>,
23291        folded: bool,
23292    },
23293    ExcerptsEdited {
23294        ids: Vec<ExcerptId>,
23295    },
23296    ExcerptsExpanded {
23297        ids: Vec<ExcerptId>,
23298    },
23299    BufferEdited,
23300    Edited {
23301        transaction_id: clock::Lamport,
23302    },
23303    Reparsed(BufferId),
23304    Focused,
23305    FocusedIn,
23306    Blurred,
23307    DirtyChanged,
23308    Saved,
23309    TitleChanged,
23310    SelectionsChanged {
23311        local: bool,
23312    },
23313    ScrollPositionChanged {
23314        local: bool,
23315        autoscroll: bool,
23316    },
23317    TransactionUndone {
23318        transaction_id: clock::Lamport,
23319    },
23320    TransactionBegun {
23321        transaction_id: clock::Lamport,
23322    },
23323    CursorShapeChanged,
23324    BreadcrumbsChanged,
23325    PushedToNavHistory {
23326        anchor: Anchor,
23327        is_deactivate: bool,
23328    },
23329}
23330
23331impl EventEmitter<EditorEvent> for Editor {}
23332
23333impl Focusable for Editor {
23334    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23335        self.focus_handle.clone()
23336    }
23337}
23338
23339impl Render for Editor {
23340    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23341        let settings = ThemeSettings::get_global(cx);
23342
23343        let mut text_style = match self.mode {
23344            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23345                color: cx.theme().colors().editor_foreground,
23346                font_family: settings.ui_font.family.clone(),
23347                font_features: settings.ui_font.features.clone(),
23348                font_fallbacks: settings.ui_font.fallbacks.clone(),
23349                font_size: rems(0.875).into(),
23350                font_weight: settings.ui_font.weight,
23351                line_height: relative(settings.buffer_line_height.value()),
23352                ..Default::default()
23353            },
23354            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23355                color: cx.theme().colors().editor_foreground,
23356                font_family: settings.buffer_font.family.clone(),
23357                font_features: settings.buffer_font.features.clone(),
23358                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23359                font_size: settings.buffer_font_size(cx).into(),
23360                font_weight: settings.buffer_font.weight,
23361                line_height: relative(settings.buffer_line_height.value()),
23362                ..Default::default()
23363            },
23364        };
23365        if let Some(text_style_refinement) = &self.text_style_refinement {
23366            text_style.refine(text_style_refinement)
23367        }
23368
23369        let background = match self.mode {
23370            EditorMode::SingleLine => cx.theme().system().transparent,
23371            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23372            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23373            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23374        };
23375
23376        EditorElement::new(
23377            &cx.entity(),
23378            EditorStyle {
23379                background,
23380                border: cx.theme().colors().border,
23381                local_player: cx.theme().players().local(),
23382                text: text_style,
23383                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23384                syntax: cx.theme().syntax().clone(),
23385                status: cx.theme().status().clone(),
23386                inlay_hints_style: make_inlay_hints_style(cx),
23387                edit_prediction_styles: make_suggestion_styles(cx),
23388                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23389                show_underlines: self.diagnostics_enabled(),
23390            },
23391        )
23392    }
23393}
23394
23395impl EntityInputHandler for Editor {
23396    fn text_for_range(
23397        &mut self,
23398        range_utf16: Range<usize>,
23399        adjusted_range: &mut Option<Range<usize>>,
23400        _: &mut Window,
23401        cx: &mut Context<Self>,
23402    ) -> Option<String> {
23403        let snapshot = self.buffer.read(cx).read(cx);
23404        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23405        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23406        if (start.0..end.0) != range_utf16 {
23407            adjusted_range.replace(start.0..end.0);
23408        }
23409        Some(snapshot.text_for_range(start..end).collect())
23410    }
23411
23412    fn selected_text_range(
23413        &mut self,
23414        ignore_disabled_input: bool,
23415        _: &mut Window,
23416        cx: &mut Context<Self>,
23417    ) -> Option<UTF16Selection> {
23418        // Prevent the IME menu from appearing when holding down an alphabetic key
23419        // while input is disabled.
23420        if !ignore_disabled_input && !self.input_enabled {
23421            return None;
23422        }
23423
23424        let selection = self.selections.newest::<OffsetUtf16>(cx);
23425        let range = selection.range();
23426
23427        Some(UTF16Selection {
23428            range: range.start.0..range.end.0,
23429            reversed: selection.reversed,
23430        })
23431    }
23432
23433    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23434        let snapshot = self.buffer.read(cx).read(cx);
23435        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23436        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23437    }
23438
23439    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23440        self.clear_highlights::<InputComposition>(cx);
23441        self.ime_transaction.take();
23442    }
23443
23444    fn replace_text_in_range(
23445        &mut self,
23446        range_utf16: Option<Range<usize>>,
23447        text: &str,
23448        window: &mut Window,
23449        cx: &mut Context<Self>,
23450    ) {
23451        if !self.input_enabled {
23452            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23453            return;
23454        }
23455
23456        self.transact(window, cx, |this, window, cx| {
23457            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23458                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23459                Some(this.selection_replacement_ranges(range_utf16, cx))
23460            } else {
23461                this.marked_text_ranges(cx)
23462            };
23463
23464            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23465                let newest_selection_id = this.selections.newest_anchor().id;
23466                this.selections
23467                    .all::<OffsetUtf16>(cx)
23468                    .iter()
23469                    .zip(ranges_to_replace.iter())
23470                    .find_map(|(selection, range)| {
23471                        if selection.id == newest_selection_id {
23472                            Some(
23473                                (range.start.0 as isize - selection.head().0 as isize)
23474                                    ..(range.end.0 as isize - selection.head().0 as isize),
23475                            )
23476                        } else {
23477                            None
23478                        }
23479                    })
23480            });
23481
23482            cx.emit(EditorEvent::InputHandled {
23483                utf16_range_to_replace: range_to_replace,
23484                text: text.into(),
23485            });
23486
23487            if let Some(new_selected_ranges) = new_selected_ranges {
23488                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23489                    selections.select_ranges(new_selected_ranges)
23490                });
23491                this.backspace(&Default::default(), window, cx);
23492            }
23493
23494            this.handle_input(text, window, cx);
23495        });
23496
23497        if let Some(transaction) = self.ime_transaction {
23498            self.buffer.update(cx, |buffer, cx| {
23499                buffer.group_until_transaction(transaction, cx);
23500            });
23501        }
23502
23503        self.unmark_text(window, cx);
23504    }
23505
23506    fn replace_and_mark_text_in_range(
23507        &mut self,
23508        range_utf16: Option<Range<usize>>,
23509        text: &str,
23510        new_selected_range_utf16: Option<Range<usize>>,
23511        window: &mut Window,
23512        cx: &mut Context<Self>,
23513    ) {
23514        if !self.input_enabled {
23515            return;
23516        }
23517
23518        let transaction = self.transact(window, cx, |this, window, cx| {
23519            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23520                let snapshot = this.buffer.read(cx).read(cx);
23521                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23522                    for marked_range in &mut marked_ranges {
23523                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23524                        marked_range.start.0 += relative_range_utf16.start;
23525                        marked_range.start =
23526                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23527                        marked_range.end =
23528                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23529                    }
23530                }
23531                Some(marked_ranges)
23532            } else if let Some(range_utf16) = range_utf16 {
23533                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23534                Some(this.selection_replacement_ranges(range_utf16, cx))
23535            } else {
23536                None
23537            };
23538
23539            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23540                let newest_selection_id = this.selections.newest_anchor().id;
23541                this.selections
23542                    .all::<OffsetUtf16>(cx)
23543                    .iter()
23544                    .zip(ranges_to_replace.iter())
23545                    .find_map(|(selection, range)| {
23546                        if selection.id == newest_selection_id {
23547                            Some(
23548                                (range.start.0 as isize - selection.head().0 as isize)
23549                                    ..(range.end.0 as isize - selection.head().0 as isize),
23550                            )
23551                        } else {
23552                            None
23553                        }
23554                    })
23555            });
23556
23557            cx.emit(EditorEvent::InputHandled {
23558                utf16_range_to_replace: range_to_replace,
23559                text: text.into(),
23560            });
23561
23562            if let Some(ranges) = ranges_to_replace {
23563                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23564                    s.select_ranges(ranges)
23565                });
23566            }
23567
23568            let marked_ranges = {
23569                let snapshot = this.buffer.read(cx).read(cx);
23570                this.selections
23571                    .disjoint_anchors()
23572                    .iter()
23573                    .map(|selection| {
23574                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23575                    })
23576                    .collect::<Vec<_>>()
23577            };
23578
23579            if text.is_empty() {
23580                this.unmark_text(window, cx);
23581            } else {
23582                this.highlight_text::<InputComposition>(
23583                    marked_ranges.clone(),
23584                    HighlightStyle {
23585                        underline: Some(UnderlineStyle {
23586                            thickness: px(1.),
23587                            color: None,
23588                            wavy: false,
23589                        }),
23590                        ..Default::default()
23591                    },
23592                    cx,
23593                );
23594            }
23595
23596            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23597            let use_autoclose = this.use_autoclose;
23598            let use_auto_surround = this.use_auto_surround;
23599            this.set_use_autoclose(false);
23600            this.set_use_auto_surround(false);
23601            this.handle_input(text, window, cx);
23602            this.set_use_autoclose(use_autoclose);
23603            this.set_use_auto_surround(use_auto_surround);
23604
23605            if let Some(new_selected_range) = new_selected_range_utf16 {
23606                let snapshot = this.buffer.read(cx).read(cx);
23607                let new_selected_ranges = marked_ranges
23608                    .into_iter()
23609                    .map(|marked_range| {
23610                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23611                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23612                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23613                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23614                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23615                    })
23616                    .collect::<Vec<_>>();
23617
23618                drop(snapshot);
23619                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23620                    selections.select_ranges(new_selected_ranges)
23621                });
23622            }
23623        });
23624
23625        self.ime_transaction = self.ime_transaction.or(transaction);
23626        if let Some(transaction) = self.ime_transaction {
23627            self.buffer.update(cx, |buffer, cx| {
23628                buffer.group_until_transaction(transaction, cx);
23629            });
23630        }
23631
23632        if self.text_highlights::<InputComposition>(cx).is_none() {
23633            self.ime_transaction.take();
23634        }
23635    }
23636
23637    fn bounds_for_range(
23638        &mut self,
23639        range_utf16: Range<usize>,
23640        element_bounds: gpui::Bounds<Pixels>,
23641        window: &mut Window,
23642        cx: &mut Context<Self>,
23643    ) -> Option<gpui::Bounds<Pixels>> {
23644        let text_layout_details = self.text_layout_details(window);
23645        let CharacterDimensions {
23646            em_width,
23647            em_advance,
23648            line_height,
23649        } = self.character_dimensions(window);
23650
23651        let snapshot = self.snapshot(window, cx);
23652        let scroll_position = snapshot.scroll_position();
23653        let scroll_left = scroll_position.x * em_advance;
23654
23655        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23656        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23657            + self.gutter_dimensions.full_width();
23658        let y = line_height * (start.row().as_f32() - scroll_position.y);
23659
23660        Some(Bounds {
23661            origin: element_bounds.origin + point(x, y),
23662            size: size(em_width, line_height),
23663        })
23664    }
23665
23666    fn character_index_for_point(
23667        &mut self,
23668        point: gpui::Point<Pixels>,
23669        _window: &mut Window,
23670        _cx: &mut Context<Self>,
23671    ) -> Option<usize> {
23672        let position_map = self.last_position_map.as_ref()?;
23673        if !position_map.text_hitbox.contains(&point) {
23674            return None;
23675        }
23676        let display_point = position_map.point_for_position(point).previous_valid;
23677        let anchor = position_map
23678            .snapshot
23679            .display_point_to_anchor(display_point, Bias::Left);
23680        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23681        Some(utf16_offset.0)
23682    }
23683}
23684
23685trait SelectionExt {
23686    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23687    fn spanned_rows(
23688        &self,
23689        include_end_if_at_line_start: bool,
23690        map: &DisplaySnapshot,
23691    ) -> Range<MultiBufferRow>;
23692}
23693
23694impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23695    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23696        let start = self
23697            .start
23698            .to_point(&map.buffer_snapshot)
23699            .to_display_point(map);
23700        let end = self
23701            .end
23702            .to_point(&map.buffer_snapshot)
23703            .to_display_point(map);
23704        if self.reversed {
23705            end..start
23706        } else {
23707            start..end
23708        }
23709    }
23710
23711    fn spanned_rows(
23712        &self,
23713        include_end_if_at_line_start: bool,
23714        map: &DisplaySnapshot,
23715    ) -> Range<MultiBufferRow> {
23716        let start = self.start.to_point(&map.buffer_snapshot);
23717        let mut end = self.end.to_point(&map.buffer_snapshot);
23718        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23719            end.row -= 1;
23720        }
23721
23722        let buffer_start = map.prev_line_boundary(start).0;
23723        let buffer_end = map.next_line_boundary(end).0;
23724        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23725    }
23726}
23727
23728impl<T: InvalidationRegion> InvalidationStack<T> {
23729    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23730    where
23731        S: Clone + ToOffset,
23732    {
23733        while let Some(region) = self.last() {
23734            let all_selections_inside_invalidation_ranges =
23735                if selections.len() == region.ranges().len() {
23736                    selections
23737                        .iter()
23738                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23739                        .all(|(selection, invalidation_range)| {
23740                            let head = selection.head().to_offset(buffer);
23741                            invalidation_range.start <= head && invalidation_range.end >= head
23742                        })
23743                } else {
23744                    false
23745                };
23746
23747            if all_selections_inside_invalidation_ranges {
23748                break;
23749            } else {
23750                self.pop();
23751            }
23752        }
23753    }
23754}
23755
23756impl<T> Default for InvalidationStack<T> {
23757    fn default() -> Self {
23758        Self(Default::default())
23759    }
23760}
23761
23762impl<T> Deref for InvalidationStack<T> {
23763    type Target = Vec<T>;
23764
23765    fn deref(&self) -> &Self::Target {
23766        &self.0
23767    }
23768}
23769
23770impl<T> DerefMut for InvalidationStack<T> {
23771    fn deref_mut(&mut self) -> &mut Self::Target {
23772        &mut self.0
23773    }
23774}
23775
23776impl InvalidationRegion for SnippetState {
23777    fn ranges(&self) -> &[Range<Anchor>] {
23778        &self.ranges[self.active_index]
23779    }
23780}
23781
23782fn edit_prediction_edit_text(
23783    current_snapshot: &BufferSnapshot,
23784    edits: &[(Range<Anchor>, String)],
23785    edit_preview: &EditPreview,
23786    include_deletions: bool,
23787    cx: &App,
23788) -> HighlightedText {
23789    let edits = edits
23790        .iter()
23791        .map(|(anchor, text)| {
23792            (
23793                anchor.start.text_anchor..anchor.end.text_anchor,
23794                text.clone(),
23795            )
23796        })
23797        .collect::<Vec<_>>();
23798
23799    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23800}
23801
23802fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23803    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23804    // Just show the raw edit text with basic styling
23805    let mut text = String::new();
23806    let mut highlights = Vec::new();
23807
23808    let insertion_highlight_style = HighlightStyle {
23809        color: Some(cx.theme().colors().text),
23810        ..Default::default()
23811    };
23812
23813    for (_, edit_text) in edits {
23814        let start_offset = text.len();
23815        text.push_str(edit_text);
23816        let end_offset = text.len();
23817
23818        if start_offset < end_offset {
23819            highlights.push((start_offset..end_offset, insertion_highlight_style));
23820        }
23821    }
23822
23823    HighlightedText {
23824        text: text.into(),
23825        highlights,
23826    }
23827}
23828
23829pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23830    match severity {
23831        lsp::DiagnosticSeverity::ERROR => colors.error,
23832        lsp::DiagnosticSeverity::WARNING => colors.warning,
23833        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23834        lsp::DiagnosticSeverity::HINT => colors.info,
23835        _ => colors.ignored,
23836    }
23837}
23838
23839pub fn styled_runs_for_code_label<'a>(
23840    label: &'a CodeLabel,
23841    syntax_theme: &'a theme::SyntaxTheme,
23842) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23843    let fade_out = HighlightStyle {
23844        fade_out: Some(0.35),
23845        ..Default::default()
23846    };
23847
23848    let mut prev_end = label.filter_range.end;
23849    label
23850        .runs
23851        .iter()
23852        .enumerate()
23853        .flat_map(move |(ix, (range, highlight_id))| {
23854            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23855                style
23856            } else {
23857                return Default::default();
23858            };
23859            let muted_style = style.highlight(fade_out);
23860
23861            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23862            if range.start >= label.filter_range.end {
23863                if range.start > prev_end {
23864                    runs.push((prev_end..range.start, fade_out));
23865                }
23866                runs.push((range.clone(), muted_style));
23867            } else if range.end <= label.filter_range.end {
23868                runs.push((range.clone(), style));
23869            } else {
23870                runs.push((range.start..label.filter_range.end, style));
23871                runs.push((label.filter_range.end..range.end, muted_style));
23872            }
23873            prev_end = cmp::max(prev_end, range.end);
23874
23875            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23876                runs.push((prev_end..label.text.len(), fade_out));
23877            }
23878
23879            runs
23880        })
23881}
23882
23883pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23884    let mut prev_index = 0;
23885    let mut prev_codepoint: Option<char> = None;
23886    text.char_indices()
23887        .chain([(text.len(), '\0')])
23888        .filter_map(move |(index, codepoint)| {
23889            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23890            let is_boundary = index == text.len()
23891                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23892                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23893            if is_boundary {
23894                let chunk = &text[prev_index..index];
23895                prev_index = index;
23896                Some(chunk)
23897            } else {
23898                None
23899            }
23900        })
23901}
23902
23903pub trait RangeToAnchorExt: Sized {
23904    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23905
23906    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23907        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23908        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23909    }
23910}
23911
23912impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23913    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23914        let start_offset = self.start.to_offset(snapshot);
23915        let end_offset = self.end.to_offset(snapshot);
23916        if start_offset == end_offset {
23917            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23918        } else {
23919            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23920        }
23921    }
23922}
23923
23924pub trait RowExt {
23925    fn as_f32(&self) -> f32;
23926
23927    fn next_row(&self) -> Self;
23928
23929    fn previous_row(&self) -> Self;
23930
23931    fn minus(&self, other: Self) -> u32;
23932}
23933
23934impl RowExt for DisplayRow {
23935    fn as_f32(&self) -> f32 {
23936        self.0 as f32
23937    }
23938
23939    fn next_row(&self) -> Self {
23940        Self(self.0 + 1)
23941    }
23942
23943    fn previous_row(&self) -> Self {
23944        Self(self.0.saturating_sub(1))
23945    }
23946
23947    fn minus(&self, other: Self) -> u32 {
23948        self.0 - other.0
23949    }
23950}
23951
23952impl RowExt for MultiBufferRow {
23953    fn as_f32(&self) -> f32 {
23954        self.0 as f32
23955    }
23956
23957    fn next_row(&self) -> Self {
23958        Self(self.0 + 1)
23959    }
23960
23961    fn previous_row(&self) -> Self {
23962        Self(self.0.saturating_sub(1))
23963    }
23964
23965    fn minus(&self, other: Self) -> u32 {
23966        self.0 - other.0
23967    }
23968}
23969
23970trait RowRangeExt {
23971    type Row;
23972
23973    fn len(&self) -> usize;
23974
23975    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23976}
23977
23978impl RowRangeExt for Range<MultiBufferRow> {
23979    type Row = MultiBufferRow;
23980
23981    fn len(&self) -> usize {
23982        (self.end.0 - self.start.0) as usize
23983    }
23984
23985    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23986        (self.start.0..self.end.0).map(MultiBufferRow)
23987    }
23988}
23989
23990impl RowRangeExt for Range<DisplayRow> {
23991    type Row = DisplayRow;
23992
23993    fn len(&self) -> usize {
23994        (self.end.0 - self.start.0) as usize
23995    }
23996
23997    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23998        (self.start.0..self.end.0).map(DisplayRow)
23999    }
24000}
24001
24002/// If select range has more than one line, we
24003/// just point the cursor to range.start.
24004fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24005    if range.start.row == range.end.row {
24006        range
24007    } else {
24008        range.start..range.start
24009    }
24010}
24011pub struct KillRing(ClipboardItem);
24012impl Global for KillRing {}
24013
24014const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24015
24016enum BreakpointPromptEditAction {
24017    Log,
24018    Condition,
24019    HitCondition,
24020}
24021
24022struct BreakpointPromptEditor {
24023    pub(crate) prompt: Entity<Editor>,
24024    editor: WeakEntity<Editor>,
24025    breakpoint_anchor: Anchor,
24026    breakpoint: Breakpoint,
24027    edit_action: BreakpointPromptEditAction,
24028    block_ids: HashSet<CustomBlockId>,
24029    editor_margins: Arc<Mutex<EditorMargins>>,
24030    _subscriptions: Vec<Subscription>,
24031}
24032
24033impl BreakpointPromptEditor {
24034    const MAX_LINES: u8 = 4;
24035
24036    fn new(
24037        editor: WeakEntity<Editor>,
24038        breakpoint_anchor: Anchor,
24039        breakpoint: Breakpoint,
24040        edit_action: BreakpointPromptEditAction,
24041        window: &mut Window,
24042        cx: &mut Context<Self>,
24043    ) -> Self {
24044        let base_text = match edit_action {
24045            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24046            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24047            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24048        }
24049        .map(|msg| msg.to_string())
24050        .unwrap_or_default();
24051
24052        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24053        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24054
24055        let prompt = cx.new(|cx| {
24056            let mut prompt = Editor::new(
24057                EditorMode::AutoHeight {
24058                    min_lines: 1,
24059                    max_lines: Some(Self::MAX_LINES as usize),
24060                },
24061                buffer,
24062                None,
24063                window,
24064                cx,
24065            );
24066            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24067            prompt.set_show_cursor_when_unfocused(false, cx);
24068            prompt.set_placeholder_text(
24069                match edit_action {
24070                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24071                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24072                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24073                },
24074                window,
24075                cx,
24076            );
24077
24078            prompt
24079        });
24080
24081        Self {
24082            prompt,
24083            editor,
24084            breakpoint_anchor,
24085            breakpoint,
24086            edit_action,
24087            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24088            block_ids: Default::default(),
24089            _subscriptions: vec![],
24090        }
24091    }
24092
24093    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24094        self.block_ids.extend(block_ids)
24095    }
24096
24097    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24098        if let Some(editor) = self.editor.upgrade() {
24099            let message = self
24100                .prompt
24101                .read(cx)
24102                .buffer
24103                .read(cx)
24104                .as_singleton()
24105                .expect("A multi buffer in breakpoint prompt isn't possible")
24106                .read(cx)
24107                .as_rope()
24108                .to_string();
24109
24110            editor.update(cx, |editor, cx| {
24111                editor.edit_breakpoint_at_anchor(
24112                    self.breakpoint_anchor,
24113                    self.breakpoint.clone(),
24114                    match self.edit_action {
24115                        BreakpointPromptEditAction::Log => {
24116                            BreakpointEditAction::EditLogMessage(message.into())
24117                        }
24118                        BreakpointPromptEditAction::Condition => {
24119                            BreakpointEditAction::EditCondition(message.into())
24120                        }
24121                        BreakpointPromptEditAction::HitCondition => {
24122                            BreakpointEditAction::EditHitCondition(message.into())
24123                        }
24124                    },
24125                    cx,
24126                );
24127
24128                editor.remove_blocks(self.block_ids.clone(), None, cx);
24129                cx.focus_self(window);
24130            });
24131        }
24132    }
24133
24134    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24135        self.editor
24136            .update(cx, |editor, cx| {
24137                editor.remove_blocks(self.block_ids.clone(), None, cx);
24138                window.focus(&editor.focus_handle);
24139            })
24140            .log_err();
24141    }
24142
24143    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24144        let settings = ThemeSettings::get_global(cx);
24145        let text_style = TextStyle {
24146            color: if self.prompt.read(cx).read_only(cx) {
24147                cx.theme().colors().text_disabled
24148            } else {
24149                cx.theme().colors().text
24150            },
24151            font_family: settings.buffer_font.family.clone(),
24152            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24153            font_size: settings.buffer_font_size(cx).into(),
24154            font_weight: settings.buffer_font.weight,
24155            line_height: relative(settings.buffer_line_height.value()),
24156            ..Default::default()
24157        };
24158        EditorElement::new(
24159            &self.prompt,
24160            EditorStyle {
24161                background: cx.theme().colors().editor_background,
24162                local_player: cx.theme().players().local(),
24163                text: text_style,
24164                ..Default::default()
24165            },
24166        )
24167    }
24168}
24169
24170impl Render for BreakpointPromptEditor {
24171    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24172        let editor_margins = *self.editor_margins.lock();
24173        let gutter_dimensions = editor_margins.gutter;
24174        h_flex()
24175            .key_context("Editor")
24176            .bg(cx.theme().colors().editor_background)
24177            .border_y_1()
24178            .border_color(cx.theme().status().info_border)
24179            .size_full()
24180            .py(window.line_height() / 2.5)
24181            .on_action(cx.listener(Self::confirm))
24182            .on_action(cx.listener(Self::cancel))
24183            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24184            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24185    }
24186}
24187
24188impl Focusable for BreakpointPromptEditor {
24189    fn focus_handle(&self, cx: &App) -> FocusHandle {
24190        self.prompt.focus_handle(cx)
24191    }
24192}
24193
24194fn all_edits_insertions_or_deletions(
24195    edits: &Vec<(Range<Anchor>, String)>,
24196    snapshot: &MultiBufferSnapshot,
24197) -> bool {
24198    let mut all_insertions = true;
24199    let mut all_deletions = true;
24200
24201    for (range, new_text) in edits.iter() {
24202        let range_is_empty = range.to_offset(snapshot).is_empty();
24203        let text_is_empty = new_text.is_empty();
24204
24205        if range_is_empty != text_is_empty {
24206            if range_is_empty {
24207                all_deletions = false;
24208            } else {
24209                all_insertions = false;
24210            }
24211        } else {
24212            return false;
24213        }
24214
24215        if !all_insertions && !all_deletions {
24216            return false;
24217        }
24218    }
24219    all_insertions || all_deletions
24220}
24221
24222struct MissingEditPredictionKeybindingTooltip;
24223
24224impl Render for MissingEditPredictionKeybindingTooltip {
24225    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24226        ui::tooltip_container(window, cx, |container, _, cx| {
24227            container
24228                .flex_shrink_0()
24229                .max_w_80()
24230                .min_h(rems_from_px(124.))
24231                .justify_between()
24232                .child(
24233                    v_flex()
24234                        .flex_1()
24235                        .text_ui_sm(cx)
24236                        .child(Label::new("Conflict with Accept Keybinding"))
24237                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24238                )
24239                .child(
24240                    h_flex()
24241                        .pb_1()
24242                        .gap_1()
24243                        .items_end()
24244                        .w_full()
24245                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24246                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
24247                        }))
24248                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24249                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24250                        })),
24251                )
24252        })
24253    }
24254}
24255
24256#[derive(Debug, Clone, Copy, PartialEq)]
24257pub struct LineHighlight {
24258    pub background: Background,
24259    pub border: Option<gpui::Hsla>,
24260    pub include_gutter: bool,
24261    pub type_id: Option<TypeId>,
24262}
24263
24264struct LineManipulationResult {
24265    pub new_text: String,
24266    pub line_count_before: usize,
24267    pub line_count_after: usize,
24268}
24269
24270fn render_diff_hunk_controls(
24271    row: u32,
24272    status: &DiffHunkStatus,
24273    hunk_range: Range<Anchor>,
24274    is_created_file: bool,
24275    line_height: Pixels,
24276    editor: &Entity<Editor>,
24277    _window: &mut Window,
24278    cx: &mut App,
24279) -> AnyElement {
24280    h_flex()
24281        .h(line_height)
24282        .mr_1()
24283        .gap_1()
24284        .px_0p5()
24285        .pb_1()
24286        .border_x_1()
24287        .border_b_1()
24288        .border_color(cx.theme().colors().border_variant)
24289        .rounded_b_lg()
24290        .bg(cx.theme().colors().editor_background)
24291        .gap_1()
24292        .block_mouse_except_scroll()
24293        .shadow_md()
24294        .child(if status.has_secondary_hunk() {
24295            Button::new(("stage", row as u64), "Stage")
24296                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24297                .tooltip({
24298                    let focus_handle = editor.focus_handle(cx);
24299                    move |window, cx| {
24300                        Tooltip::for_action_in(
24301                            "Stage Hunk",
24302                            &::git::ToggleStaged,
24303                            &focus_handle,
24304                            window,
24305                            cx,
24306                        )
24307                    }
24308                })
24309                .on_click({
24310                    let editor = editor.clone();
24311                    move |_event, _window, cx| {
24312                        editor.update(cx, |editor, cx| {
24313                            editor.stage_or_unstage_diff_hunks(
24314                                true,
24315                                vec![hunk_range.start..hunk_range.start],
24316                                cx,
24317                            );
24318                        });
24319                    }
24320                })
24321        } else {
24322            Button::new(("unstage", row as u64), "Unstage")
24323                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24324                .tooltip({
24325                    let focus_handle = editor.focus_handle(cx);
24326                    move |window, cx| {
24327                        Tooltip::for_action_in(
24328                            "Unstage Hunk",
24329                            &::git::ToggleStaged,
24330                            &focus_handle,
24331                            window,
24332                            cx,
24333                        )
24334                    }
24335                })
24336                .on_click({
24337                    let editor = editor.clone();
24338                    move |_event, _window, cx| {
24339                        editor.update(cx, |editor, cx| {
24340                            editor.stage_or_unstage_diff_hunks(
24341                                false,
24342                                vec![hunk_range.start..hunk_range.start],
24343                                cx,
24344                            );
24345                        });
24346                    }
24347                })
24348        })
24349        .child(
24350            Button::new(("restore", row as u64), "Restore")
24351                .tooltip({
24352                    let focus_handle = editor.focus_handle(cx);
24353                    move |window, cx| {
24354                        Tooltip::for_action_in(
24355                            "Restore Hunk",
24356                            &::git::Restore,
24357                            &focus_handle,
24358                            window,
24359                            cx,
24360                        )
24361                    }
24362                })
24363                .on_click({
24364                    let editor = editor.clone();
24365                    move |_event, window, cx| {
24366                        editor.update(cx, |editor, cx| {
24367                            let snapshot = editor.snapshot(window, cx);
24368                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
24369                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24370                        });
24371                    }
24372                })
24373                .disabled(is_created_file),
24374        )
24375        .when(
24376            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24377            |el| {
24378                el.child(
24379                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24380                        .shape(IconButtonShape::Square)
24381                        .icon_size(IconSize::Small)
24382                        // .disabled(!has_multiple_hunks)
24383                        .tooltip({
24384                            let focus_handle = editor.focus_handle(cx);
24385                            move |window, cx| {
24386                                Tooltip::for_action_in(
24387                                    "Next Hunk",
24388                                    &GoToHunk,
24389                                    &focus_handle,
24390                                    window,
24391                                    cx,
24392                                )
24393                            }
24394                        })
24395                        .on_click({
24396                            let editor = editor.clone();
24397                            move |_event, window, cx| {
24398                                editor.update(cx, |editor, cx| {
24399                                    let snapshot = editor.snapshot(window, cx);
24400                                    let position =
24401                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
24402                                    editor.go_to_hunk_before_or_after_position(
24403                                        &snapshot,
24404                                        position,
24405                                        Direction::Next,
24406                                        window,
24407                                        cx,
24408                                    );
24409                                    editor.expand_selected_diff_hunks(cx);
24410                                });
24411                            }
24412                        }),
24413                )
24414                .child(
24415                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24416                        .shape(IconButtonShape::Square)
24417                        .icon_size(IconSize::Small)
24418                        // .disabled(!has_multiple_hunks)
24419                        .tooltip({
24420                            let focus_handle = editor.focus_handle(cx);
24421                            move |window, cx| {
24422                                Tooltip::for_action_in(
24423                                    "Previous Hunk",
24424                                    &GoToPreviousHunk,
24425                                    &focus_handle,
24426                                    window,
24427                                    cx,
24428                                )
24429                            }
24430                        })
24431                        .on_click({
24432                            let editor = editor.clone();
24433                            move |_event, window, cx| {
24434                                editor.update(cx, |editor, cx| {
24435                                    let snapshot = editor.snapshot(window, cx);
24436                                    let point =
24437                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24438                                    editor.go_to_hunk_before_or_after_position(
24439                                        &snapshot,
24440                                        point,
24441                                        Direction::Prev,
24442                                        window,
24443                                        cx,
24444                                    );
24445                                    editor.expand_selected_diff_hunks(cx);
24446                                });
24447                            }
24448                        }),
24449                )
24450            },
24451        )
24452        .into_any_element()
24453}
24454
24455pub fn multibuffer_context_lines(cx: &App) -> u32 {
24456    EditorSettings::try_get(cx)
24457        .map(|settings| settings.excerpt_context_lines)
24458        .unwrap_or(2)
24459        .min(32)
24460}