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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt, StreamExt as _,
   78    future::{self, Shared, join},
   79    stream::FuturesUnordered,
   80};
   81use fuzzy::{StringMatch, StringMatchCandidate};
   82
   83use ::git::blame::BlameEntry;
   84use ::git::{Restore, blame::ParsedCommitMessage};
   85use code_context_menus::{
   86    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   87    CompletionsMenu, ContextMenuOrigin,
   88};
   89use git::blame::{GitBlame, GlobalBlameRenderer};
   90use gpui::{
   91    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   92    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   93    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   94    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   95    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   96    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   97    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   98    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   99};
  100use highlight_matching_bracket::refresh_matching_bracket_highlights;
  101use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  102pub use hover_popover::hover_markdown_style;
  103use hover_popover::{HoverState, hide_hover};
  104use indent_guides::ActiveIndentGuidesState;
  105use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  106pub use inline_completion::Direction;
  107use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  108pub use items::MAX_TAB_TITLE_LEN;
  109use itertools::Itertools;
  110use language::{
  111    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  112    CursorShape, DiagnosticEntry, DiagnosticSourceKind, DiffOptions, DocumentationConfig,
  113    EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize, Language,
  114    OffsetRangeExt, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  115    WordsQuery,
  116    language_settings::{
  117        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  118        all_language_settings, language_settings,
  119    },
  120    point_from_lsp, text_diff_with_options,
  121};
  122use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  123use linked_editing_ranges::refresh_linked_ranges;
  124use markdown::Markdown;
  125use mouse_context_menu::MouseContextMenu;
  126use persistence::DB;
  127use project::{
  128    BreakpointWithPosition, CompletionResponse, LspPullDiagnostics, ProjectPath, PulledDiagnostics,
  129    debugger::{
  130        breakpoint_store::{
  131            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  132            BreakpointStoreEvent,
  133        },
  134        session::{Session, SessionEvent},
  135    },
  136    project_settings::DiagnosticSeverity,
  137};
  138
  139pub use git::blame::BlameRenderer;
  140pub use proposed_changes_editor::{
  141    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  142};
  143use std::{cell::OnceCell, iter::Peekable, ops::Not};
  144use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  145
  146pub use lsp::CompletionContext;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId, LanguageServerName,
  150};
  151
  152use language::BufferSnapshot;
  153pub use lsp_ext::lsp_tasks;
  154use movement::TextLayoutDetails;
  155pub use multi_buffer::{
  156    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  157    RowInfo, ToOffset, ToPoint,
  158};
  159use multi_buffer::{
  160    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  161    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  162};
  163use parking_lot::Mutex;
  164use project::{
  165    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  166    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  167    TaskSourceKind,
  168    debugger::breakpoint_store::Breakpoint,
  169    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  170    project_settings::{GitGutterSetting, ProjectSettings},
  171};
  172use rand::prelude::*;
  173use rpc::{ErrorExt, proto::*};
  174use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  175use selections_collection::{
  176    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  177};
  178use serde::{Deserialize, Serialize};
  179use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  180use smallvec::{SmallVec, smallvec};
  181use snippet::Snippet;
  182use std::sync::Arc;
  183use std::{
  184    any::TypeId,
  185    borrow::Cow,
  186    cell::RefCell,
  187    cmp::{self, Ordering, Reverse},
  188    mem,
  189    num::NonZeroU32,
  190    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  191    path::{Path, PathBuf},
  192    rc::Rc,
  193    time::{Duration, Instant},
  194};
  195pub use sum_tree::Bias;
  196use sum_tree::TreeMap;
  197use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  198use theme::{
  199    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  200    observe_buffer_font_size_adjustment,
  201};
  202use ui::{
  203    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  204    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  205};
  206use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  207use workspace::{
  208    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  209    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  210    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  211    item::{ItemHandle, PreviewTabsSettings},
  212    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  213    searchable::SearchEvent,
  214};
  215
  216use crate::{
  217    code_context_menus::CompletionsMenuSource,
  218    hover_links::{find_url, find_url_from_range},
  219};
  220use crate::{
  221    editor_settings::MultiCursorModifier,
  222    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  223};
  224
  225pub const FILE_HEADER_HEIGHT: u32 = 2;
  226pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  227pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  228const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  229const MAX_LINE_LEN: usize = 1024;
  230const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  231const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  232pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  233#[doc(hidden)]
  234pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  235const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  236
  237pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  238pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  239pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  240
  241pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  242pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  243pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  244pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  245
  246pub type RenderDiffHunkControlsFn = Arc<
  247    dyn Fn(
  248        u32,
  249        &DiffHunkStatus,
  250        Range<Anchor>,
  251        bool,
  252        Pixels,
  253        &Entity<Editor>,
  254        &mut Window,
  255        &mut App,
  256    ) -> AnyElement,
  257>;
  258
  259struct InlineValueCache {
  260    enabled: bool,
  261    inlays: Vec<InlayId>,
  262    refresh_task: Task<Option<()>>,
  263}
  264
  265impl InlineValueCache {
  266    fn new(enabled: bool) -> Self {
  267        Self {
  268            enabled,
  269            inlays: Vec::new(),
  270            refresh_task: Task::ready(None),
  271        }
  272    }
  273}
  274
  275#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  276pub enum InlayId {
  277    InlineCompletion(usize),
  278    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297pub enum PendingInput {}
  298enum SelectedTextHighlight {}
  299
  300pub enum ConflictsOuter {}
  301pub enum ConflictsOurs {}
  302pub enum ConflictsTheirs {}
  303pub enum ConflictsOursMarker {}
  304pub enum ConflictsTheirsMarker {}
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329    },
  330}
  331
  332pub enum HideMouseCursorOrigin {
  333    TypingAction,
  334    MovementAction,
  335}
  336
  337pub fn init_settings(cx: &mut App) {
  338    EditorSettings::register(cx);
  339}
  340
  341pub fn init(cx: &mut App) {
  342    init_settings(cx);
  343
  344    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  345
  346    workspace::register_project_item::<Editor>(cx);
  347    workspace::FollowableViewRegistry::register::<Editor>(cx);
  348    workspace::register_serializable_item::<Editor>(cx);
  349
  350    cx.observe_new(
  351        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  352            workspace.register_action(Editor::new_file);
  353            workspace.register_action(Editor::new_file_vertical);
  354            workspace.register_action(Editor::new_file_horizontal);
  355            workspace.register_action(Editor::cancel_language_server_work);
  356        },
  357    )
  358    .detach();
  359
  360    cx.on_action(move |_: &workspace::NewFile, cx| {
  361        let app_state = workspace::AppState::global(cx);
  362        if let Some(app_state) = app_state.upgrade() {
  363            workspace::open_new(
  364                Default::default(),
  365                app_state,
  366                cx,
  367                |workspace, window, cx| {
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374    cx.on_action(move |_: &workspace::NewWindow, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    cx.activate(true);
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389}
  390
  391pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  392    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  393}
  394
  395pub trait DiagnosticRenderer {
  396    fn render_group(
  397        &self,
  398        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  399        buffer_id: BufferId,
  400        snapshot: EditorSnapshot,
  401        editor: WeakEntity<Editor>,
  402        cx: &mut App,
  403    ) -> Vec<BlockProperties<Anchor>>;
  404
  405    fn render_hover(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        range: Range<Point>,
  409        buffer_id: BufferId,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug)]
  466pub enum SelectMode {
  467    Character,
  468    Word(Range<Anchor>),
  469    Line(Range<Anchor>),
  470    All,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine {
  476        auto_width: bool,
  477    },
  478    AutoHeight {
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled {
  721        /// The configuration currently present in the users settings.
  722        setting_configuration: bool,
  723        /// Whether to override the currently set visibility from the users setting.
  724        toggle_override: bool,
  725    },
  726}
  727
  728impl MinimapVisibility {
  729    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  730        if mode.is_full() {
  731            Self::Enabled {
  732                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  733                toggle_override: false,
  734            }
  735        } else {
  736            Self::Disabled
  737        }
  738    }
  739
  740    fn hidden(&self) -> Self {
  741        match *self {
  742            Self::Enabled {
  743                setting_configuration,
  744                ..
  745            } => Self::Enabled {
  746                setting_configuration,
  747                toggle_override: setting_configuration,
  748            },
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752
  753    fn disabled(&self) -> bool {
  754        match *self {
  755            Self::Disabled => true,
  756            _ => false,
  757        }
  758    }
  759
  760    fn settings_visibility(&self) -> bool {
  761        match *self {
  762            Self::Enabled {
  763                setting_configuration,
  764                ..
  765            } => setting_configuration,
  766            _ => false,
  767        }
  768    }
  769
  770    fn visible(&self) -> bool {
  771        match *self {
  772            Self::Enabled {
  773                setting_configuration,
  774                toggle_override,
  775            } => setting_configuration ^ toggle_override,
  776            _ => false,
  777        }
  778    }
  779
  780    fn toggle_visibility(&self) -> Self {
  781        match *self {
  782            Self::Enabled {
  783                toggle_override,
  784                setting_configuration,
  785            } => Self::Enabled {
  786                setting_configuration,
  787                toggle_override: !toggle_override,
  788            },
  789            Self::Disabled => Self::Disabled,
  790        }
  791    }
  792}
  793
  794#[derive(Clone, Debug)]
  795struct RunnableTasks {
  796    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  797    offset: multi_buffer::Anchor,
  798    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  799    column: u32,
  800    // Values of all named captures, including those starting with '_'
  801    extra_variables: HashMap<String, String>,
  802    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  803    context_range: Range<BufferOffset>,
  804}
  805
  806impl RunnableTasks {
  807    fn resolve<'a>(
  808        &'a self,
  809        cx: &'a task::TaskContext,
  810    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  811        self.templates.iter().filter_map(|(kind, template)| {
  812            template
  813                .resolve_task(&kind.to_id_base(), cx)
  814                .map(|task| (kind.clone(), task))
  815        })
  816    }
  817}
  818
  819#[derive(Clone)]
  820pub struct ResolvedTasks {
  821    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  822    position: Anchor,
  823}
  824
  825#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  826struct BufferOffset(usize);
  827
  828// Addons allow storing per-editor state in other crates (e.g. Vim)
  829pub trait Addon: 'static {
  830    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  831
  832    fn render_buffer_header_controls(
  833        &self,
  834        _: &ExcerptInfo,
  835        _: &Window,
  836        _: &App,
  837    ) -> Option<AnyElement> {
  838        None
  839    }
  840
  841    fn to_any(&self) -> &dyn std::any::Any;
  842
  843    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  844        None
  845    }
  846}
  847
  848/// A set of caret positions, registered when the editor was edited.
  849pub struct ChangeList {
  850    changes: Vec<Vec<Anchor>>,
  851    /// Currently "selected" change.
  852    position: Option<usize>,
  853}
  854
  855impl ChangeList {
  856    pub fn new() -> Self {
  857        Self {
  858            changes: Vec::new(),
  859            position: None,
  860        }
  861    }
  862
  863    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  864    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  865    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  866        if self.changes.is_empty() {
  867            return None;
  868        }
  869
  870        let prev = self.position.unwrap_or(self.changes.len());
  871        let next = if direction == Direction::Prev {
  872            prev.saturating_sub(count)
  873        } else {
  874            (prev + count).min(self.changes.len() - 1)
  875        };
  876        self.position = Some(next);
  877        self.changes.get(next).map(|anchors| anchors.as_slice())
  878    }
  879
  880    /// Adds a new change to the list, resetting the change list position.
  881    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  882        self.position.take();
  883        if pop_state {
  884            self.changes.pop();
  885        }
  886        self.changes.push(new_positions.clone());
  887    }
  888
  889    pub fn last(&self) -> Option<&[Anchor]> {
  890        self.changes.last().map(|anchors| anchors.as_slice())
  891    }
  892}
  893
  894#[derive(Clone)]
  895struct InlineBlamePopoverState {
  896    scroll_handle: ScrollHandle,
  897    commit_message: Option<ParsedCommitMessage>,
  898    markdown: Entity<Markdown>,
  899}
  900
  901struct InlineBlamePopover {
  902    position: gpui::Point<Pixels>,
  903    show_task: Option<Task<()>>,
  904    hide_task: Option<Task<()>>,
  905    popover_bounds: Option<Bounds<Pixels>>,
  906    popover_state: InlineBlamePopoverState,
  907}
  908
  909enum SelectionDragState {
  910    /// State when no drag related activity is detected.
  911    None,
  912    /// State when the mouse is down on a selection that is about to be dragged.
  913    ReadyToDrag {
  914        selection: Selection<Anchor>,
  915        click_position: gpui::Point<Pixels>,
  916    },
  917    /// State when the mouse is dragging the selection in the editor.
  918    Dragging {
  919        selection: Selection<Anchor>,
  920        drop_cursor: Selection<Anchor>,
  921    },
  922}
  923
  924/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  925/// a breakpoint on them.
  926#[derive(Clone, Copy, Debug)]
  927struct PhantomBreakpointIndicator {
  928    display_row: DisplayRow,
  929    /// There's a small debounce between hovering over the line and showing the indicator.
  930    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  931    is_active: bool,
  932    collides_with_existing_breakpoint: bool,
  933}
  934/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  935///
  936/// See the [module level documentation](self) for more information.
  937pub struct Editor {
  938    focus_handle: FocusHandle,
  939    last_focused_descendant: Option<WeakFocusHandle>,
  940    /// The text buffer being edited
  941    buffer: Entity<MultiBuffer>,
  942    /// Map of how text in the buffer should be displayed.
  943    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  944    pub display_map: Entity<DisplayMap>,
  945    pub selections: SelectionsCollection,
  946    pub scroll_manager: ScrollManager,
  947    /// When inline assist editors are linked, they all render cursors because
  948    /// typing enters text into each of them, even the ones that aren't focused.
  949    pub(crate) show_cursor_when_unfocused: bool,
  950    columnar_selection_tail: Option<Anchor>,
  951    columnar_display_point: Option<DisplayPoint>,
  952    add_selections_state: Option<AddSelectionsState>,
  953    select_next_state: Option<SelectNextState>,
  954    select_prev_state: Option<SelectNextState>,
  955    selection_history: SelectionHistory,
  956    defer_selection_effects: bool,
  957    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  958    autoclose_regions: Vec<AutocloseRegion>,
  959    snippet_stack: InvalidationStack<SnippetState>,
  960    select_syntax_node_history: SelectSyntaxNodeHistory,
  961    ime_transaction: Option<TransactionId>,
  962    pub diagnostics_max_severity: DiagnosticSeverity,
  963    active_diagnostics: ActiveDiagnostic,
  964    show_inline_diagnostics: bool,
  965    inline_diagnostics_update: Task<()>,
  966    inline_diagnostics_enabled: bool,
  967    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  968    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  969    hard_wrap: Option<usize>,
  970
  971    // TODO: make this a access method
  972    pub project: Option<Entity<Project>>,
  973    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  974    completion_provider: Option<Rc<dyn CompletionProvider>>,
  975    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  976    blink_manager: Entity<BlinkManager>,
  977    show_cursor_names: bool,
  978    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  979    pub show_local_selections: bool,
  980    mode: EditorMode,
  981    show_breadcrumbs: bool,
  982    show_gutter: bool,
  983    show_scrollbars: ScrollbarAxes,
  984    minimap_visibility: MinimapVisibility,
  985    offset_content: bool,
  986    disable_expand_excerpt_buttons: bool,
  987    show_line_numbers: Option<bool>,
  988    use_relative_line_numbers: Option<bool>,
  989    show_git_diff_gutter: Option<bool>,
  990    show_code_actions: Option<bool>,
  991    show_runnables: Option<bool>,
  992    show_breakpoints: Option<bool>,
  993    show_wrap_guides: Option<bool>,
  994    show_indent_guides: Option<bool>,
  995    placeholder_text: Option<Arc<str>>,
  996    highlight_order: usize,
  997    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  998    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  999    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1000    scrollbar_marker_state: ScrollbarMarkerState,
 1001    active_indent_guides_state: ActiveIndentGuidesState,
 1002    nav_history: Option<ItemNavHistory>,
 1003    context_menu: RefCell<Option<CodeContextMenu>>,
 1004    context_menu_options: Option<ContextMenuOptions>,
 1005    mouse_context_menu: Option<MouseContextMenu>,
 1006    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1007    inline_blame_popover: Option<InlineBlamePopover>,
 1008    signature_help_state: SignatureHelpState,
 1009    auto_signature_help: Option<bool>,
 1010    find_all_references_task_sources: Vec<Anchor>,
 1011    next_completion_id: CompletionId,
 1012    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1013    code_actions_task: Option<Task<Result<()>>>,
 1014    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1015    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1016    document_highlights_task: Option<Task<()>>,
 1017    linked_editing_range_task: Option<Task<Option<()>>>,
 1018    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1019    pending_rename: Option<RenameState>,
 1020    searchable: bool,
 1021    cursor_shape: CursorShape,
 1022    current_line_highlight: Option<CurrentLineHighlight>,
 1023    collapse_matches: bool,
 1024    autoindent_mode: Option<AutoindentMode>,
 1025    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1026    input_enabled: bool,
 1027    use_modal_editing: bool,
 1028    read_only: bool,
 1029    leader_id: Option<CollaboratorId>,
 1030    remote_id: Option<ViewId>,
 1031    pub hover_state: HoverState,
 1032    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1033    gutter_hovered: bool,
 1034    hovered_link_state: Option<HoveredLinkState>,
 1035    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1036    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1037    active_inline_completion: Option<InlineCompletionState>,
 1038    /// Used to prevent flickering as the user types while the menu is open
 1039    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1040    edit_prediction_settings: EditPredictionSettings,
 1041    inline_completions_hidden_for_vim_mode: bool,
 1042    show_inline_completions_override: Option<bool>,
 1043    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1044    edit_prediction_preview: EditPredictionPreview,
 1045    edit_prediction_indent_conflict: bool,
 1046    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1047    inlay_hint_cache: InlayHintCache,
 1048    next_inlay_id: usize,
 1049    _subscriptions: Vec<Subscription>,
 1050    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1051    gutter_dimensions: GutterDimensions,
 1052    style: Option<EditorStyle>,
 1053    text_style_refinement: Option<TextStyleRefinement>,
 1054    next_editor_action_id: EditorActionId,
 1055    editor_actions:
 1056        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1057    use_autoclose: bool,
 1058    use_auto_surround: bool,
 1059    auto_replace_emoji_shortcode: bool,
 1060    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1061    show_git_blame_gutter: bool,
 1062    show_git_blame_inline: bool,
 1063    show_git_blame_inline_delay_task: Option<Task<()>>,
 1064    git_blame_inline_enabled: bool,
 1065    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1066    serialize_dirty_buffers: bool,
 1067    show_selection_menu: Option<bool>,
 1068    blame: Option<Entity<GitBlame>>,
 1069    blame_subscription: Option<Subscription>,
 1070    custom_context_menu: Option<
 1071        Box<
 1072            dyn 'static
 1073                + Fn(
 1074                    &mut Self,
 1075                    DisplayPoint,
 1076                    &mut Window,
 1077                    &mut Context<Self>,
 1078                ) -> Option<Entity<ui::ContextMenu>>,
 1079        >,
 1080    >,
 1081    last_bounds: Option<Bounds<Pixels>>,
 1082    last_position_map: Option<Rc<PositionMap>>,
 1083    expect_bounds_change: Option<Bounds<Pixels>>,
 1084    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1085    tasks_update_task: Option<Task<()>>,
 1086    breakpoint_store: Option<Entity<BreakpointStore>>,
 1087    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1088    pull_diagnostics_task: Task<()>,
 1089    in_project_search: bool,
 1090    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1091    breadcrumb_header: Option<String>,
 1092    focused_block: Option<FocusedBlock>,
 1093    next_scroll_position: NextScrollCursorCenterTopBottom,
 1094    addons: HashMap<TypeId, Box<dyn Addon>>,
 1095    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1096    load_diff_task: Option<Shared<Task<()>>>,
 1097    /// Whether we are temporarily displaying a diff other than git's
 1098    temporary_diff_override: bool,
 1099    selection_mark_mode: bool,
 1100    toggle_fold_multiple_buffers: Task<()>,
 1101    _scroll_cursor_center_top_bottom_task: Task<()>,
 1102    serialize_selections: Task<()>,
 1103    serialize_folds: Task<()>,
 1104    mouse_cursor_hidden: bool,
 1105    minimap: Option<Entity<Self>>,
 1106    hide_mouse_mode: HideMouseMode,
 1107    pub change_list: ChangeList,
 1108    inline_value_cache: InlineValueCache,
 1109    selection_drag_state: SelectionDragState,
 1110    drag_and_drop_selection_enabled: bool,
 1111}
 1112
 1113#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1114enum NextScrollCursorCenterTopBottom {
 1115    #[default]
 1116    Center,
 1117    Top,
 1118    Bottom,
 1119}
 1120
 1121impl NextScrollCursorCenterTopBottom {
 1122    fn next(&self) -> Self {
 1123        match self {
 1124            Self::Center => Self::Top,
 1125            Self::Top => Self::Bottom,
 1126            Self::Bottom => Self::Center,
 1127        }
 1128    }
 1129}
 1130
 1131#[derive(Clone)]
 1132pub struct EditorSnapshot {
 1133    pub mode: EditorMode,
 1134    show_gutter: bool,
 1135    show_line_numbers: Option<bool>,
 1136    show_git_diff_gutter: Option<bool>,
 1137    show_code_actions: Option<bool>,
 1138    show_runnables: Option<bool>,
 1139    show_breakpoints: Option<bool>,
 1140    git_blame_gutter_max_author_length: Option<usize>,
 1141    pub display_snapshot: DisplaySnapshot,
 1142    pub placeholder_text: Option<Arc<str>>,
 1143    is_focused: bool,
 1144    scroll_anchor: ScrollAnchor,
 1145    ongoing_scroll: OngoingScroll,
 1146    current_line_highlight: CurrentLineHighlight,
 1147    gutter_hovered: bool,
 1148}
 1149
 1150#[derive(Default, Debug, Clone, Copy)]
 1151pub struct GutterDimensions {
 1152    pub left_padding: Pixels,
 1153    pub right_padding: Pixels,
 1154    pub width: Pixels,
 1155    pub margin: Pixels,
 1156    pub git_blame_entries_width: Option<Pixels>,
 1157}
 1158
 1159impl GutterDimensions {
 1160    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1161        Self {
 1162            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1163            ..Default::default()
 1164        }
 1165    }
 1166
 1167    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1168        -cx.text_system().descent(font_id, font_size)
 1169    }
 1170    /// The full width of the space taken up by the gutter.
 1171    pub fn full_width(&self) -> Pixels {
 1172        self.margin + self.width
 1173    }
 1174
 1175    /// The width of the space reserved for the fold indicators,
 1176    /// use alongside 'justify_end' and `gutter_width` to
 1177    /// right align content with the line numbers
 1178    pub fn fold_area_width(&self) -> Pixels {
 1179        self.margin + self.right_padding
 1180    }
 1181}
 1182
 1183#[derive(Debug)]
 1184pub struct RemoteSelection {
 1185    pub replica_id: ReplicaId,
 1186    pub selection: Selection<Anchor>,
 1187    pub cursor_shape: CursorShape,
 1188    pub collaborator_id: CollaboratorId,
 1189    pub line_mode: bool,
 1190    pub user_name: Option<SharedString>,
 1191    pub color: PlayerColor,
 1192}
 1193
 1194#[derive(Clone, Debug)]
 1195struct SelectionHistoryEntry {
 1196    selections: Arc<[Selection<Anchor>]>,
 1197    select_next_state: Option<SelectNextState>,
 1198    select_prev_state: Option<SelectNextState>,
 1199    add_selections_state: Option<AddSelectionsState>,
 1200}
 1201
 1202enum SelectionHistoryMode {
 1203    Normal,
 1204    Undoing,
 1205    Redoing,
 1206}
 1207
 1208#[derive(Clone, PartialEq, Eq, Hash)]
 1209struct HoveredCursor {
 1210    replica_id: u16,
 1211    selection_id: usize,
 1212}
 1213
 1214impl Default for SelectionHistoryMode {
 1215    fn default() -> Self {
 1216        Self::Normal
 1217    }
 1218}
 1219
 1220struct DeferredSelectionEffectsState {
 1221    changed: bool,
 1222    should_update_completions: bool,
 1223    autoscroll: Option<Autoscroll>,
 1224    old_cursor_position: Anchor,
 1225    history_entry: SelectionHistoryEntry,
 1226}
 1227
 1228#[derive(Default)]
 1229struct SelectionHistory {
 1230    #[allow(clippy::type_complexity)]
 1231    selections_by_transaction:
 1232        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1233    mode: SelectionHistoryMode,
 1234    undo_stack: VecDeque<SelectionHistoryEntry>,
 1235    redo_stack: VecDeque<SelectionHistoryEntry>,
 1236}
 1237
 1238impl SelectionHistory {
 1239    fn insert_transaction(
 1240        &mut self,
 1241        transaction_id: TransactionId,
 1242        selections: Arc<[Selection<Anchor>]>,
 1243    ) {
 1244        self.selections_by_transaction
 1245            .insert(transaction_id, (selections, None));
 1246    }
 1247
 1248    #[allow(clippy::type_complexity)]
 1249    fn transaction(
 1250        &self,
 1251        transaction_id: TransactionId,
 1252    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1253        self.selections_by_transaction.get(&transaction_id)
 1254    }
 1255
 1256    #[allow(clippy::type_complexity)]
 1257    fn transaction_mut(
 1258        &mut self,
 1259        transaction_id: TransactionId,
 1260    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1261        self.selections_by_transaction.get_mut(&transaction_id)
 1262    }
 1263
 1264    fn push(&mut self, entry: SelectionHistoryEntry) {
 1265        if !entry.selections.is_empty() {
 1266            match self.mode {
 1267                SelectionHistoryMode::Normal => {
 1268                    self.push_undo(entry);
 1269                    self.redo_stack.clear();
 1270                }
 1271                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1272                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1273            }
 1274        }
 1275    }
 1276
 1277    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1278        if self
 1279            .undo_stack
 1280            .back()
 1281            .map_or(true, |e| e.selections != entry.selections)
 1282        {
 1283            self.undo_stack.push_back(entry);
 1284            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1285                self.undo_stack.pop_front();
 1286            }
 1287        }
 1288    }
 1289
 1290    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1291        if self
 1292            .redo_stack
 1293            .back()
 1294            .map_or(true, |e| e.selections != entry.selections)
 1295        {
 1296            self.redo_stack.push_back(entry);
 1297            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1298                self.redo_stack.pop_front();
 1299            }
 1300        }
 1301    }
 1302}
 1303
 1304#[derive(Clone, Copy)]
 1305pub struct RowHighlightOptions {
 1306    pub autoscroll: bool,
 1307    pub include_gutter: bool,
 1308}
 1309
 1310impl Default for RowHighlightOptions {
 1311    fn default() -> Self {
 1312        Self {
 1313            autoscroll: Default::default(),
 1314            include_gutter: true,
 1315        }
 1316    }
 1317}
 1318
 1319struct RowHighlight {
 1320    index: usize,
 1321    range: Range<Anchor>,
 1322    color: Hsla,
 1323    options: RowHighlightOptions,
 1324    type_id: TypeId,
 1325}
 1326
 1327#[derive(Clone, Debug)]
 1328struct AddSelectionsState {
 1329    groups: Vec<AddSelectionsGroup>,
 1330}
 1331
 1332#[derive(Clone, Debug)]
 1333struct AddSelectionsGroup {
 1334    above: bool,
 1335    stack: Vec<usize>,
 1336}
 1337
 1338#[derive(Clone)]
 1339struct SelectNextState {
 1340    query: AhoCorasick,
 1341    wordwise: bool,
 1342    done: bool,
 1343}
 1344
 1345impl std::fmt::Debug for SelectNextState {
 1346    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1347        f.debug_struct(std::any::type_name::<Self>())
 1348            .field("wordwise", &self.wordwise)
 1349            .field("done", &self.done)
 1350            .finish()
 1351    }
 1352}
 1353
 1354#[derive(Debug)]
 1355struct AutocloseRegion {
 1356    selection_id: usize,
 1357    range: Range<Anchor>,
 1358    pair: BracketPair,
 1359}
 1360
 1361#[derive(Debug)]
 1362struct SnippetState {
 1363    ranges: Vec<Vec<Range<Anchor>>>,
 1364    active_index: usize,
 1365    choices: Vec<Option<Vec<String>>>,
 1366}
 1367
 1368#[doc(hidden)]
 1369pub struct RenameState {
 1370    pub range: Range<Anchor>,
 1371    pub old_name: Arc<str>,
 1372    pub editor: Entity<Editor>,
 1373    block_id: CustomBlockId,
 1374}
 1375
 1376struct InvalidationStack<T>(Vec<T>);
 1377
 1378struct RegisteredInlineCompletionProvider {
 1379    provider: Arc<dyn InlineCompletionProviderHandle>,
 1380    _subscription: Subscription,
 1381}
 1382
 1383#[derive(Debug, PartialEq, Eq)]
 1384pub struct ActiveDiagnosticGroup {
 1385    pub active_range: Range<Anchor>,
 1386    pub active_message: String,
 1387    pub group_id: usize,
 1388    pub blocks: HashSet<CustomBlockId>,
 1389}
 1390
 1391#[derive(Debug, PartialEq, Eq)]
 1392
 1393pub(crate) enum ActiveDiagnostic {
 1394    None,
 1395    All,
 1396    Group(ActiveDiagnosticGroup),
 1397}
 1398
 1399#[derive(Serialize, Deserialize, Clone, Debug)]
 1400pub struct ClipboardSelection {
 1401    /// The number of bytes in this selection.
 1402    pub len: usize,
 1403    /// Whether this was a full-line selection.
 1404    pub is_entire_line: bool,
 1405    /// The indentation of the first line when this content was originally copied.
 1406    pub first_line_indent: u32,
 1407}
 1408
 1409// selections, scroll behavior, was newest selection reversed
 1410type SelectSyntaxNodeHistoryState = (
 1411    Box<[Selection<usize>]>,
 1412    SelectSyntaxNodeScrollBehavior,
 1413    bool,
 1414);
 1415
 1416#[derive(Default)]
 1417struct SelectSyntaxNodeHistory {
 1418    stack: Vec<SelectSyntaxNodeHistoryState>,
 1419    // disable temporarily to allow changing selections without losing the stack
 1420    pub disable_clearing: bool,
 1421}
 1422
 1423impl SelectSyntaxNodeHistory {
 1424    pub fn try_clear(&mut self) {
 1425        if !self.disable_clearing {
 1426            self.stack.clear();
 1427        }
 1428    }
 1429
 1430    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1431        self.stack.push(selection);
 1432    }
 1433
 1434    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1435        self.stack.pop()
 1436    }
 1437}
 1438
 1439enum SelectSyntaxNodeScrollBehavior {
 1440    CursorTop,
 1441    FitSelection,
 1442    CursorBottom,
 1443}
 1444
 1445#[derive(Debug)]
 1446pub(crate) struct NavigationData {
 1447    cursor_anchor: Anchor,
 1448    cursor_position: Point,
 1449    scroll_anchor: ScrollAnchor,
 1450    scroll_top_row: u32,
 1451}
 1452
 1453#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1454pub enum GotoDefinitionKind {
 1455    Symbol,
 1456    Declaration,
 1457    Type,
 1458    Implementation,
 1459}
 1460
 1461#[derive(Debug, Clone)]
 1462enum InlayHintRefreshReason {
 1463    ModifiersChanged(bool),
 1464    Toggle(bool),
 1465    SettingsChange(InlayHintSettings),
 1466    NewLinesShown,
 1467    BufferEdited(HashSet<Arc<Language>>),
 1468    RefreshRequested,
 1469    ExcerptsRemoved(Vec<ExcerptId>),
 1470}
 1471
 1472impl InlayHintRefreshReason {
 1473    fn description(&self) -> &'static str {
 1474        match self {
 1475            Self::ModifiersChanged(_) => "modifiers changed",
 1476            Self::Toggle(_) => "toggle",
 1477            Self::SettingsChange(_) => "settings change",
 1478            Self::NewLinesShown => "new lines shown",
 1479            Self::BufferEdited(_) => "buffer edited",
 1480            Self::RefreshRequested => "refresh requested",
 1481            Self::ExcerptsRemoved(_) => "excerpts removed",
 1482        }
 1483    }
 1484}
 1485
 1486pub enum FormatTarget {
 1487    Buffers,
 1488    Ranges(Vec<Range<MultiBufferPoint>>),
 1489}
 1490
 1491pub(crate) struct FocusedBlock {
 1492    id: BlockId,
 1493    focus_handle: WeakFocusHandle,
 1494}
 1495
 1496#[derive(Clone)]
 1497enum JumpData {
 1498    MultiBufferRow {
 1499        row: MultiBufferRow,
 1500        line_offset_from_top: u32,
 1501    },
 1502    MultiBufferPoint {
 1503        excerpt_id: ExcerptId,
 1504        position: Point,
 1505        anchor: text::Anchor,
 1506        line_offset_from_top: u32,
 1507    },
 1508}
 1509
 1510pub enum MultibufferSelectionMode {
 1511    First,
 1512    All,
 1513}
 1514
 1515#[derive(Clone, Copy, Debug, Default)]
 1516pub struct RewrapOptions {
 1517    pub override_language_settings: bool,
 1518    pub preserve_existing_whitespace: bool,
 1519}
 1520
 1521impl Editor {
 1522    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1523        let buffer = cx.new(|cx| Buffer::local("", cx));
 1524        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1525        Self::new(
 1526            EditorMode::SingleLine { auto_width: false },
 1527            buffer,
 1528            None,
 1529            window,
 1530            cx,
 1531        )
 1532    }
 1533
 1534    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1535        let buffer = cx.new(|cx| Buffer::local("", cx));
 1536        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1537        Self::new(EditorMode::full(), buffer, None, window, cx)
 1538    }
 1539
 1540    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1541        let buffer = cx.new(|cx| Buffer::local("", cx));
 1542        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1543        Self::new(
 1544            EditorMode::SingleLine { auto_width: true },
 1545            buffer,
 1546            None,
 1547            window,
 1548            cx,
 1549        )
 1550    }
 1551
 1552    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1553        let buffer = cx.new(|cx| Buffer::local("", cx));
 1554        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1555        Self::new(
 1556            EditorMode::AutoHeight { max_lines },
 1557            buffer,
 1558            None,
 1559            window,
 1560            cx,
 1561        )
 1562    }
 1563
 1564    pub fn for_buffer(
 1565        buffer: Entity<Buffer>,
 1566        project: Option<Entity<Project>>,
 1567        window: &mut Window,
 1568        cx: &mut Context<Self>,
 1569    ) -> Self {
 1570        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1571        Self::new(EditorMode::full(), buffer, project, window, cx)
 1572    }
 1573
 1574    pub fn for_multibuffer(
 1575        buffer: Entity<MultiBuffer>,
 1576        project: Option<Entity<Project>>,
 1577        window: &mut Window,
 1578        cx: &mut Context<Self>,
 1579    ) -> Self {
 1580        Self::new(EditorMode::full(), buffer, project, window, cx)
 1581    }
 1582
 1583    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1584        let mut clone = Self::new(
 1585            self.mode.clone(),
 1586            self.buffer.clone(),
 1587            self.project.clone(),
 1588            window,
 1589            cx,
 1590        );
 1591        self.display_map.update(cx, |display_map, cx| {
 1592            let snapshot = display_map.snapshot(cx);
 1593            clone.display_map.update(cx, |display_map, cx| {
 1594                display_map.set_state(&snapshot, cx);
 1595            });
 1596        });
 1597        clone.folds_did_change(cx);
 1598        clone.selections.clone_state(&self.selections);
 1599        clone.scroll_manager.clone_state(&self.scroll_manager);
 1600        clone.searchable = self.searchable;
 1601        clone.read_only = self.read_only;
 1602        clone
 1603    }
 1604
 1605    pub fn new(
 1606        mode: EditorMode,
 1607        buffer: Entity<MultiBuffer>,
 1608        project: Option<Entity<Project>>,
 1609        window: &mut Window,
 1610        cx: &mut Context<Self>,
 1611    ) -> Self {
 1612        Editor::new_internal(mode, buffer, project, None, window, cx)
 1613    }
 1614
 1615    fn new_internal(
 1616        mode: EditorMode,
 1617        buffer: Entity<MultiBuffer>,
 1618        project: Option<Entity<Project>>,
 1619        display_map: Option<Entity<DisplayMap>>,
 1620        window: &mut Window,
 1621        cx: &mut Context<Self>,
 1622    ) -> Self {
 1623        debug_assert!(
 1624            display_map.is_none() || mode.is_minimap(),
 1625            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1626        );
 1627
 1628        let full_mode = mode.is_full();
 1629        let diagnostics_max_severity = if full_mode {
 1630            EditorSettings::get_global(cx)
 1631                .diagnostics_max_severity
 1632                .unwrap_or(DiagnosticSeverity::Hint)
 1633        } else {
 1634            DiagnosticSeverity::Off
 1635        };
 1636        let style = window.text_style();
 1637        let font_size = style.font_size.to_pixels(window.rem_size());
 1638        let editor = cx.entity().downgrade();
 1639        let fold_placeholder = FoldPlaceholder {
 1640            constrain_width: true,
 1641            render: Arc::new(move |fold_id, fold_range, cx| {
 1642                let editor = editor.clone();
 1643                div()
 1644                    .id(fold_id)
 1645                    .bg(cx.theme().colors().ghost_element_background)
 1646                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1647                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1648                    .rounded_xs()
 1649                    .size_full()
 1650                    .cursor_pointer()
 1651                    .child("")
 1652                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1653                    .on_click(move |_, _window, cx| {
 1654                        editor
 1655                            .update(cx, |editor, cx| {
 1656                                editor.unfold_ranges(
 1657                                    &[fold_range.start..fold_range.end],
 1658                                    true,
 1659                                    false,
 1660                                    cx,
 1661                                );
 1662                                cx.stop_propagation();
 1663                            })
 1664                            .ok();
 1665                    })
 1666                    .into_any()
 1667            }),
 1668            merge_adjacent: true,
 1669            ..FoldPlaceholder::default()
 1670        };
 1671        let display_map = display_map.unwrap_or_else(|| {
 1672            cx.new(|cx| {
 1673                DisplayMap::new(
 1674                    buffer.clone(),
 1675                    style.font(),
 1676                    font_size,
 1677                    None,
 1678                    FILE_HEADER_HEIGHT,
 1679                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1680                    fold_placeholder,
 1681                    diagnostics_max_severity,
 1682                    cx,
 1683                )
 1684            })
 1685        });
 1686
 1687        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1688
 1689        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1690
 1691        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1692            .then(|| language_settings::SoftWrap::None);
 1693
 1694        let mut project_subscriptions = Vec::new();
 1695        if mode.is_full() {
 1696            if let Some(project) = project.as_ref() {
 1697                project_subscriptions.push(cx.subscribe_in(
 1698                    project,
 1699                    window,
 1700                    |editor, _, event, window, cx| match event {
 1701                        project::Event::RefreshCodeLens => {
 1702                            // we always query lens with actions, without storing them, always refreshing them
 1703                        }
 1704                        project::Event::RefreshInlayHints => {
 1705                            editor
 1706                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1707                        }
 1708                        project::Event::LanguageServerAdded(..)
 1709                        | project::Event::LanguageServerRemoved(..) => {
 1710                            if editor.tasks_update_task.is_none() {
 1711                                editor.tasks_update_task =
 1712                                    Some(editor.refresh_runnables(window, cx));
 1713                            }
 1714                            editor.pull_diagnostics(None, window, cx);
 1715                        }
 1716                        project::Event::SnippetEdit(id, snippet_edits) => {
 1717                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1718                                let focus_handle = editor.focus_handle(cx);
 1719                                if focus_handle.is_focused(window) {
 1720                                    let snapshot = buffer.read(cx).snapshot();
 1721                                    for (range, snippet) in snippet_edits {
 1722                                        let editor_range =
 1723                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1724                                        editor
 1725                                            .insert_snippet(
 1726                                                &[editor_range],
 1727                                                snippet.clone(),
 1728                                                window,
 1729                                                cx,
 1730                                            )
 1731                                            .ok();
 1732                                    }
 1733                                }
 1734                            }
 1735                        }
 1736                        _ => {}
 1737                    },
 1738                ));
 1739                if let Some(task_inventory) = project
 1740                    .read(cx)
 1741                    .task_store()
 1742                    .read(cx)
 1743                    .task_inventory()
 1744                    .cloned()
 1745                {
 1746                    project_subscriptions.push(cx.observe_in(
 1747                        &task_inventory,
 1748                        window,
 1749                        |editor, _, window, cx| {
 1750                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1751                        },
 1752                    ));
 1753                };
 1754
 1755                project_subscriptions.push(cx.subscribe_in(
 1756                    &project.read(cx).breakpoint_store(),
 1757                    window,
 1758                    |editor, _, event, window, cx| match event {
 1759                        BreakpointStoreEvent::ClearDebugLines => {
 1760                            editor.clear_row_highlights::<ActiveDebugLine>();
 1761                            editor.refresh_inline_values(cx);
 1762                        }
 1763                        BreakpointStoreEvent::SetDebugLine => {
 1764                            if editor.go_to_active_debug_line(window, cx) {
 1765                                cx.stop_propagation();
 1766                            }
 1767
 1768                            editor.refresh_inline_values(cx);
 1769                        }
 1770                        _ => {}
 1771                    },
 1772                ));
 1773            }
 1774        }
 1775
 1776        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1777
 1778        let inlay_hint_settings =
 1779            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1780        let focus_handle = cx.focus_handle();
 1781        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1782            .detach();
 1783        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1784            .detach();
 1785        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1786            .detach();
 1787        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1788            .detach();
 1789        cx.observe_pending_input(window, Self::observe_pending_input)
 1790            .detach();
 1791
 1792        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1793            Some(false)
 1794        } else {
 1795            None
 1796        };
 1797
 1798        let breakpoint_store = match (&mode, project.as_ref()) {
 1799            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1800            _ => None,
 1801        };
 1802
 1803        let mut code_action_providers = Vec::new();
 1804        let mut load_uncommitted_diff = None;
 1805        if let Some(project) = project.clone() {
 1806            load_uncommitted_diff = Some(
 1807                update_uncommitted_diff_for_buffer(
 1808                    cx.entity(),
 1809                    &project,
 1810                    buffer.read(cx).all_buffers(),
 1811                    buffer.clone(),
 1812                    cx,
 1813                )
 1814                .shared(),
 1815            );
 1816            code_action_providers.push(Rc::new(project) as Rc<_>);
 1817        }
 1818
 1819        let mut editor = Self {
 1820            focus_handle,
 1821            show_cursor_when_unfocused: false,
 1822            last_focused_descendant: None,
 1823            buffer: buffer.clone(),
 1824            display_map: display_map.clone(),
 1825            selections,
 1826            scroll_manager: ScrollManager::new(cx),
 1827            columnar_selection_tail: None,
 1828            columnar_display_point: None,
 1829            add_selections_state: None,
 1830            select_next_state: None,
 1831            select_prev_state: None,
 1832            selection_history: SelectionHistory::default(),
 1833            defer_selection_effects: false,
 1834            deferred_selection_effects_state: None,
 1835            autoclose_regions: Vec::new(),
 1836            snippet_stack: InvalidationStack::default(),
 1837            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1838            ime_transaction: None,
 1839            active_diagnostics: ActiveDiagnostic::None,
 1840            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1841            inline_diagnostics_update: Task::ready(()),
 1842            inline_diagnostics: Vec::new(),
 1843            soft_wrap_mode_override,
 1844            diagnostics_max_severity,
 1845            hard_wrap: None,
 1846            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1847            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1848            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1849            project,
 1850            blink_manager: blink_manager.clone(),
 1851            show_local_selections: true,
 1852            show_scrollbars: ScrollbarAxes {
 1853                horizontal: full_mode,
 1854                vertical: full_mode,
 1855            },
 1856            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1857            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1858            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1859            show_gutter: mode.is_full(),
 1860            show_line_numbers: None,
 1861            use_relative_line_numbers: None,
 1862            disable_expand_excerpt_buttons: false,
 1863            show_git_diff_gutter: None,
 1864            show_code_actions: None,
 1865            show_runnables: None,
 1866            show_breakpoints: None,
 1867            show_wrap_guides: None,
 1868            show_indent_guides,
 1869            placeholder_text: None,
 1870            highlight_order: 0,
 1871            highlighted_rows: HashMap::default(),
 1872            background_highlights: TreeMap::default(),
 1873            gutter_highlights: TreeMap::default(),
 1874            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1875            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1876            nav_history: None,
 1877            context_menu: RefCell::new(None),
 1878            context_menu_options: None,
 1879            mouse_context_menu: None,
 1880            completion_tasks: Vec::new(),
 1881            inline_blame_popover: None,
 1882            signature_help_state: SignatureHelpState::default(),
 1883            auto_signature_help: None,
 1884            find_all_references_task_sources: Vec::new(),
 1885            next_completion_id: 0,
 1886            next_inlay_id: 0,
 1887            code_action_providers,
 1888            available_code_actions: None,
 1889            code_actions_task: None,
 1890            quick_selection_highlight_task: None,
 1891            debounced_selection_highlight_task: None,
 1892            document_highlights_task: None,
 1893            linked_editing_range_task: None,
 1894            pending_rename: None,
 1895            searchable: true,
 1896            cursor_shape: EditorSettings::get_global(cx)
 1897                .cursor_shape
 1898                .unwrap_or_default(),
 1899            current_line_highlight: None,
 1900            autoindent_mode: Some(AutoindentMode::EachLine),
 1901            collapse_matches: false,
 1902            workspace: None,
 1903            input_enabled: true,
 1904            use_modal_editing: mode.is_full(),
 1905            read_only: mode.is_minimap(),
 1906            use_autoclose: true,
 1907            use_auto_surround: true,
 1908            auto_replace_emoji_shortcode: false,
 1909            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1910            leader_id: None,
 1911            remote_id: None,
 1912            hover_state: HoverState::default(),
 1913            pending_mouse_down: None,
 1914            hovered_link_state: None,
 1915            edit_prediction_provider: None,
 1916            active_inline_completion: None,
 1917            stale_inline_completion_in_menu: None,
 1918            edit_prediction_preview: EditPredictionPreview::Inactive {
 1919                released_too_fast: false,
 1920            },
 1921            inline_diagnostics_enabled: mode.is_full(),
 1922            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1923            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1924
 1925            gutter_hovered: false,
 1926            pixel_position_of_newest_cursor: None,
 1927            last_bounds: None,
 1928            last_position_map: None,
 1929            expect_bounds_change: None,
 1930            gutter_dimensions: GutterDimensions::default(),
 1931            style: None,
 1932            show_cursor_names: false,
 1933            hovered_cursors: HashMap::default(),
 1934            next_editor_action_id: EditorActionId::default(),
 1935            editor_actions: Rc::default(),
 1936            inline_completions_hidden_for_vim_mode: false,
 1937            show_inline_completions_override: None,
 1938            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1939            edit_prediction_settings: EditPredictionSettings::Disabled,
 1940            edit_prediction_indent_conflict: false,
 1941            edit_prediction_requires_modifier_in_indent_conflict: true,
 1942            custom_context_menu: None,
 1943            show_git_blame_gutter: false,
 1944            show_git_blame_inline: false,
 1945            show_selection_menu: None,
 1946            show_git_blame_inline_delay_task: None,
 1947            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1948            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1949            serialize_dirty_buffers: !mode.is_minimap()
 1950                && ProjectSettings::get_global(cx)
 1951                    .session
 1952                    .restore_unsaved_buffers,
 1953            blame: None,
 1954            blame_subscription: None,
 1955            tasks: BTreeMap::default(),
 1956
 1957            breakpoint_store,
 1958            gutter_breakpoint_indicator: (None, None),
 1959            _subscriptions: vec![
 1960                cx.observe(&buffer, Self::on_buffer_changed),
 1961                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1962                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1963                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1964                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1965                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1966                cx.observe_window_activation(window, |editor, window, cx| {
 1967                    let active = window.is_window_active();
 1968                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1969                        if active {
 1970                            blink_manager.enable(cx);
 1971                        } else {
 1972                            blink_manager.disable(cx);
 1973                        }
 1974                    });
 1975                    if active {
 1976                        editor.show_mouse_cursor();
 1977                    }
 1978                }),
 1979            ],
 1980            tasks_update_task: None,
 1981            pull_diagnostics_task: Task::ready(()),
 1982            linked_edit_ranges: Default::default(),
 1983            in_project_search: false,
 1984            previous_search_ranges: None,
 1985            breadcrumb_header: None,
 1986            focused_block: None,
 1987            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1988            addons: HashMap::default(),
 1989            registered_buffers: HashMap::default(),
 1990            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1991            selection_mark_mode: false,
 1992            toggle_fold_multiple_buffers: Task::ready(()),
 1993            serialize_selections: Task::ready(()),
 1994            serialize_folds: Task::ready(()),
 1995            text_style_refinement: None,
 1996            load_diff_task: load_uncommitted_diff,
 1997            temporary_diff_override: false,
 1998            mouse_cursor_hidden: false,
 1999            minimap: None,
 2000            hide_mouse_mode: EditorSettings::get_global(cx)
 2001                .hide_mouse
 2002                .unwrap_or_default(),
 2003            change_list: ChangeList::new(),
 2004            mode,
 2005            selection_drag_state: SelectionDragState::None,
 2006            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2007        };
 2008        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2009            editor
 2010                ._subscriptions
 2011                .push(cx.observe(breakpoints, |_, _, cx| {
 2012                    cx.notify();
 2013                }));
 2014        }
 2015        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2016        editor._subscriptions.extend(project_subscriptions);
 2017
 2018        editor._subscriptions.push(cx.subscribe_in(
 2019            &cx.entity(),
 2020            window,
 2021            |editor, _, e: &EditorEvent, window, cx| match e {
 2022                EditorEvent::ScrollPositionChanged { local, .. } => {
 2023                    if *local {
 2024                        let new_anchor = editor.scroll_manager.anchor();
 2025                        let snapshot = editor.snapshot(window, cx);
 2026                        editor.update_restoration_data(cx, move |data| {
 2027                            data.scroll_position = (
 2028                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2029                                new_anchor.offset,
 2030                            );
 2031                        });
 2032                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2033                        editor.inline_blame_popover.take();
 2034                    }
 2035                }
 2036                EditorEvent::Edited { .. } => {
 2037                    if !vim_enabled(cx) {
 2038                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2039                        let pop_state = editor
 2040                            .change_list
 2041                            .last()
 2042                            .map(|previous| {
 2043                                previous.len() == selections.len()
 2044                                    && previous.iter().enumerate().all(|(ix, p)| {
 2045                                        p.to_display_point(&map).row()
 2046                                            == selections[ix].head().row()
 2047                                    })
 2048                            })
 2049                            .unwrap_or(false);
 2050                        let new_positions = selections
 2051                            .into_iter()
 2052                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2053                            .collect();
 2054                        editor
 2055                            .change_list
 2056                            .push_to_change_list(pop_state, new_positions);
 2057                    }
 2058                }
 2059                _ => (),
 2060            },
 2061        ));
 2062
 2063        if let Some(dap_store) = editor
 2064            .project
 2065            .as_ref()
 2066            .map(|project| project.read(cx).dap_store())
 2067        {
 2068            let weak_editor = cx.weak_entity();
 2069
 2070            editor
 2071                ._subscriptions
 2072                .push(
 2073                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2074                        let session_entity = cx.entity();
 2075                        weak_editor
 2076                            .update(cx, |editor, cx| {
 2077                                editor._subscriptions.push(
 2078                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2079                                );
 2080                            })
 2081                            .ok();
 2082                    }),
 2083                );
 2084
 2085            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2086                editor
 2087                    ._subscriptions
 2088                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2089            }
 2090        }
 2091
 2092        editor.end_selection(window, cx);
 2093        editor.scroll_manager.show_scrollbars(window, cx);
 2094        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2095
 2096        if full_mode {
 2097            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2098            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2099
 2100            if editor.git_blame_inline_enabled {
 2101                editor.start_git_blame_inline(false, window, cx);
 2102            }
 2103
 2104            editor.go_to_active_debug_line(window, cx);
 2105
 2106            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2107                if let Some(project) = editor.project.as_ref() {
 2108                    let handle = project.update(cx, |project, cx| {
 2109                        project.register_buffer_with_language_servers(&buffer, cx)
 2110                    });
 2111                    editor
 2112                        .registered_buffers
 2113                        .insert(buffer.read(cx).remote_id(), handle);
 2114                }
 2115            }
 2116
 2117            editor.minimap =
 2118                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2119            editor.pull_diagnostics(None, window, cx);
 2120        }
 2121
 2122        editor.report_editor_event("Editor Opened", None, cx);
 2123        editor
 2124    }
 2125
 2126    pub fn deploy_mouse_context_menu(
 2127        &mut self,
 2128        position: gpui::Point<Pixels>,
 2129        context_menu: Entity<ContextMenu>,
 2130        window: &mut Window,
 2131        cx: &mut Context<Self>,
 2132    ) {
 2133        self.mouse_context_menu = Some(MouseContextMenu::new(
 2134            self,
 2135            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2136            context_menu,
 2137            window,
 2138            cx,
 2139        ));
 2140    }
 2141
 2142    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2143        self.mouse_context_menu
 2144            .as_ref()
 2145            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2146    }
 2147
 2148    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2149        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2150    }
 2151
 2152    fn key_context_internal(
 2153        &self,
 2154        has_active_edit_prediction: bool,
 2155        window: &Window,
 2156        cx: &App,
 2157    ) -> KeyContext {
 2158        let mut key_context = KeyContext::new_with_defaults();
 2159        key_context.add("Editor");
 2160        let mode = match self.mode {
 2161            EditorMode::SingleLine { .. } => "single_line",
 2162            EditorMode::AutoHeight { .. } => "auto_height",
 2163            EditorMode::Minimap { .. } => "minimap",
 2164            EditorMode::Full { .. } => "full",
 2165        };
 2166
 2167        if EditorSettings::jupyter_enabled(cx) {
 2168            key_context.add("jupyter");
 2169        }
 2170
 2171        key_context.set("mode", mode);
 2172        if self.pending_rename.is_some() {
 2173            key_context.add("renaming");
 2174        }
 2175
 2176        match self.context_menu.borrow().as_ref() {
 2177            Some(CodeContextMenu::Completions(_)) => {
 2178                key_context.add("menu");
 2179                key_context.add("showing_completions");
 2180            }
 2181            Some(CodeContextMenu::CodeActions(_)) => {
 2182                key_context.add("menu");
 2183                key_context.add("showing_code_actions")
 2184            }
 2185            None => {}
 2186        }
 2187
 2188        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2189        if !self.focus_handle(cx).contains_focused(window, cx)
 2190            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2191        {
 2192            for addon in self.addons.values() {
 2193                addon.extend_key_context(&mut key_context, cx)
 2194            }
 2195        }
 2196
 2197        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2198            if let Some(extension) = singleton_buffer
 2199                .read(cx)
 2200                .file()
 2201                .and_then(|file| file.path().extension()?.to_str())
 2202            {
 2203                key_context.set("extension", extension.to_string());
 2204            }
 2205        } else {
 2206            key_context.add("multibuffer");
 2207        }
 2208
 2209        if has_active_edit_prediction {
 2210            if self.edit_prediction_in_conflict() {
 2211                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2212            } else {
 2213                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2214                key_context.add("copilot_suggestion");
 2215            }
 2216        }
 2217
 2218        if self.selection_mark_mode {
 2219            key_context.add("selection_mode");
 2220        }
 2221
 2222        key_context
 2223    }
 2224
 2225    fn show_mouse_cursor(&mut self) {
 2226        self.mouse_cursor_hidden = false;
 2227    }
 2228
 2229    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2230        self.mouse_cursor_hidden = match origin {
 2231            HideMouseCursorOrigin::TypingAction => {
 2232                matches!(
 2233                    self.hide_mouse_mode,
 2234                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2235                )
 2236            }
 2237            HideMouseCursorOrigin::MovementAction => {
 2238                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2239            }
 2240        };
 2241    }
 2242
 2243    pub fn edit_prediction_in_conflict(&self) -> bool {
 2244        if !self.show_edit_predictions_in_menu() {
 2245            return false;
 2246        }
 2247
 2248        let showing_completions = self
 2249            .context_menu
 2250            .borrow()
 2251            .as_ref()
 2252            .map_or(false, |context| {
 2253                matches!(context, CodeContextMenu::Completions(_))
 2254            });
 2255
 2256        showing_completions
 2257            || self.edit_prediction_requires_modifier()
 2258            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2259            // bindings to insert tab characters.
 2260            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2261    }
 2262
 2263    pub fn accept_edit_prediction_keybind(
 2264        &self,
 2265        accept_partial: bool,
 2266        window: &Window,
 2267        cx: &App,
 2268    ) -> AcceptEditPredictionBinding {
 2269        let key_context = self.key_context_internal(true, window, cx);
 2270        let in_conflict = self.edit_prediction_in_conflict();
 2271
 2272        let bindings = if accept_partial {
 2273            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2274        } else {
 2275            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2276        };
 2277
 2278        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2279        // just the first one.
 2280        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2281            !in_conflict
 2282                || binding
 2283                    .keystrokes()
 2284                    .first()
 2285                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2286        }))
 2287    }
 2288
 2289    pub fn new_file(
 2290        workspace: &mut Workspace,
 2291        _: &workspace::NewFile,
 2292        window: &mut Window,
 2293        cx: &mut Context<Workspace>,
 2294    ) {
 2295        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2296            "Failed to create buffer",
 2297            window,
 2298            cx,
 2299            |e, _, _| match e.error_code() {
 2300                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2301                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2302                e.error_tag("required").unwrap_or("the latest version")
 2303            )),
 2304                _ => None,
 2305            },
 2306        );
 2307    }
 2308
 2309    pub fn new_in_workspace(
 2310        workspace: &mut Workspace,
 2311        window: &mut Window,
 2312        cx: &mut Context<Workspace>,
 2313    ) -> Task<Result<Entity<Editor>>> {
 2314        let project = workspace.project().clone();
 2315        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2316
 2317        cx.spawn_in(window, async move |workspace, cx| {
 2318            let buffer = create.await?;
 2319            workspace.update_in(cx, |workspace, window, cx| {
 2320                let editor =
 2321                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2322                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2323                editor
 2324            })
 2325        })
 2326    }
 2327
 2328    fn new_file_vertical(
 2329        workspace: &mut Workspace,
 2330        _: &workspace::NewFileSplitVertical,
 2331        window: &mut Window,
 2332        cx: &mut Context<Workspace>,
 2333    ) {
 2334        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2335    }
 2336
 2337    fn new_file_horizontal(
 2338        workspace: &mut Workspace,
 2339        _: &workspace::NewFileSplitHorizontal,
 2340        window: &mut Window,
 2341        cx: &mut Context<Workspace>,
 2342    ) {
 2343        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2344    }
 2345
 2346    fn new_file_in_direction(
 2347        workspace: &mut Workspace,
 2348        direction: SplitDirection,
 2349        window: &mut Window,
 2350        cx: &mut Context<Workspace>,
 2351    ) {
 2352        let project = workspace.project().clone();
 2353        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2354
 2355        cx.spawn_in(window, async move |workspace, cx| {
 2356            let buffer = create.await?;
 2357            workspace.update_in(cx, move |workspace, window, cx| {
 2358                workspace.split_item(
 2359                    direction,
 2360                    Box::new(
 2361                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2362                    ),
 2363                    window,
 2364                    cx,
 2365                )
 2366            })?;
 2367            anyhow::Ok(())
 2368        })
 2369        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2370            match e.error_code() {
 2371                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2372                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2373                e.error_tag("required").unwrap_or("the latest version")
 2374            )),
 2375                _ => None,
 2376            }
 2377        });
 2378    }
 2379
 2380    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2381        self.leader_id
 2382    }
 2383
 2384    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2385        &self.buffer
 2386    }
 2387
 2388    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2389        self.workspace.as_ref()?.0.upgrade()
 2390    }
 2391
 2392    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2393        self.buffer().read(cx).title(cx)
 2394    }
 2395
 2396    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2397        let git_blame_gutter_max_author_length = self
 2398            .render_git_blame_gutter(cx)
 2399            .then(|| {
 2400                if let Some(blame) = self.blame.as_ref() {
 2401                    let max_author_length =
 2402                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2403                    Some(max_author_length)
 2404                } else {
 2405                    None
 2406                }
 2407            })
 2408            .flatten();
 2409
 2410        EditorSnapshot {
 2411            mode: self.mode.clone(),
 2412            show_gutter: self.show_gutter,
 2413            show_line_numbers: self.show_line_numbers,
 2414            show_git_diff_gutter: self.show_git_diff_gutter,
 2415            show_code_actions: self.show_code_actions,
 2416            show_runnables: self.show_runnables,
 2417            show_breakpoints: self.show_breakpoints,
 2418            git_blame_gutter_max_author_length,
 2419            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2420            scroll_anchor: self.scroll_manager.anchor(),
 2421            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2422            placeholder_text: self.placeholder_text.clone(),
 2423            is_focused: self.focus_handle.is_focused(window),
 2424            current_line_highlight: self
 2425                .current_line_highlight
 2426                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2427            gutter_hovered: self.gutter_hovered,
 2428        }
 2429    }
 2430
 2431    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2432        self.buffer.read(cx).language_at(point, cx)
 2433    }
 2434
 2435    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2436        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2437    }
 2438
 2439    pub fn active_excerpt(
 2440        &self,
 2441        cx: &App,
 2442    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2443        self.buffer
 2444            .read(cx)
 2445            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2446    }
 2447
 2448    pub fn mode(&self) -> &EditorMode {
 2449        &self.mode
 2450    }
 2451
 2452    pub fn set_mode(&mut self, mode: EditorMode) {
 2453        self.mode = mode;
 2454    }
 2455
 2456    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2457        self.collaboration_hub.as_deref()
 2458    }
 2459
 2460    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2461        self.collaboration_hub = Some(hub);
 2462    }
 2463
 2464    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2465        self.in_project_search = in_project_search;
 2466    }
 2467
 2468    pub fn set_custom_context_menu(
 2469        &mut self,
 2470        f: impl 'static
 2471        + Fn(
 2472            &mut Self,
 2473            DisplayPoint,
 2474            &mut Window,
 2475            &mut Context<Self>,
 2476        ) -> Option<Entity<ui::ContextMenu>>,
 2477    ) {
 2478        self.custom_context_menu = Some(Box::new(f))
 2479    }
 2480
 2481    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2482        self.completion_provider = provider;
 2483    }
 2484
 2485    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2486        self.semantics_provider.clone()
 2487    }
 2488
 2489    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2490        self.semantics_provider = provider;
 2491    }
 2492
 2493    pub fn set_edit_prediction_provider<T>(
 2494        &mut self,
 2495        provider: Option<Entity<T>>,
 2496        window: &mut Window,
 2497        cx: &mut Context<Self>,
 2498    ) where
 2499        T: EditPredictionProvider,
 2500    {
 2501        self.edit_prediction_provider =
 2502            provider.map(|provider| RegisteredInlineCompletionProvider {
 2503                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2504                    if this.focus_handle.is_focused(window) {
 2505                        this.update_visible_inline_completion(window, cx);
 2506                    }
 2507                }),
 2508                provider: Arc::new(provider),
 2509            });
 2510        self.update_edit_prediction_settings(cx);
 2511        self.refresh_inline_completion(false, false, window, cx);
 2512    }
 2513
 2514    pub fn placeholder_text(&self) -> Option<&str> {
 2515        self.placeholder_text.as_deref()
 2516    }
 2517
 2518    pub fn set_placeholder_text(
 2519        &mut self,
 2520        placeholder_text: impl Into<Arc<str>>,
 2521        cx: &mut Context<Self>,
 2522    ) {
 2523        let placeholder_text = Some(placeholder_text.into());
 2524        if self.placeholder_text != placeholder_text {
 2525            self.placeholder_text = placeholder_text;
 2526            cx.notify();
 2527        }
 2528    }
 2529
 2530    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2531        self.cursor_shape = cursor_shape;
 2532
 2533        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2534        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2535
 2536        cx.notify();
 2537    }
 2538
 2539    pub fn set_current_line_highlight(
 2540        &mut self,
 2541        current_line_highlight: Option<CurrentLineHighlight>,
 2542    ) {
 2543        self.current_line_highlight = current_line_highlight;
 2544    }
 2545
 2546    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2547        self.collapse_matches = collapse_matches;
 2548    }
 2549
 2550    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2551        let buffers = self.buffer.read(cx).all_buffers();
 2552        let Some(project) = self.project.as_ref() else {
 2553            return;
 2554        };
 2555        project.update(cx, |project, cx| {
 2556            for buffer in buffers {
 2557                self.registered_buffers
 2558                    .entry(buffer.read(cx).remote_id())
 2559                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2560            }
 2561        })
 2562    }
 2563
 2564    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2565        if self.collapse_matches {
 2566            return range.start..range.start;
 2567        }
 2568        range.clone()
 2569    }
 2570
 2571    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2572        if self.display_map.read(cx).clip_at_line_ends != clip {
 2573            self.display_map
 2574                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2575        }
 2576    }
 2577
 2578    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2579        self.input_enabled = input_enabled;
 2580    }
 2581
 2582    pub fn set_inline_completions_hidden_for_vim_mode(
 2583        &mut self,
 2584        hidden: bool,
 2585        window: &mut Window,
 2586        cx: &mut Context<Self>,
 2587    ) {
 2588        if hidden != self.inline_completions_hidden_for_vim_mode {
 2589            self.inline_completions_hidden_for_vim_mode = hidden;
 2590            if hidden {
 2591                self.update_visible_inline_completion(window, cx);
 2592            } else {
 2593                self.refresh_inline_completion(true, false, window, cx);
 2594            }
 2595        }
 2596    }
 2597
 2598    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2599        self.menu_inline_completions_policy = value;
 2600    }
 2601
 2602    pub fn set_autoindent(&mut self, autoindent: bool) {
 2603        if autoindent {
 2604            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2605        } else {
 2606            self.autoindent_mode = None;
 2607        }
 2608    }
 2609
 2610    pub fn read_only(&self, cx: &App) -> bool {
 2611        self.read_only || self.buffer.read(cx).read_only()
 2612    }
 2613
 2614    pub fn set_read_only(&mut self, read_only: bool) {
 2615        self.read_only = read_only;
 2616    }
 2617
 2618    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2619        self.use_autoclose = autoclose;
 2620    }
 2621
 2622    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2623        self.use_auto_surround = auto_surround;
 2624    }
 2625
 2626    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2627        self.auto_replace_emoji_shortcode = auto_replace;
 2628    }
 2629
 2630    pub fn toggle_edit_predictions(
 2631        &mut self,
 2632        _: &ToggleEditPrediction,
 2633        window: &mut Window,
 2634        cx: &mut Context<Self>,
 2635    ) {
 2636        if self.show_inline_completions_override.is_some() {
 2637            self.set_show_edit_predictions(None, window, cx);
 2638        } else {
 2639            let show_edit_predictions = !self.edit_predictions_enabled();
 2640            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2641        }
 2642    }
 2643
 2644    pub fn set_show_edit_predictions(
 2645        &mut self,
 2646        show_edit_predictions: Option<bool>,
 2647        window: &mut Window,
 2648        cx: &mut Context<Self>,
 2649    ) {
 2650        self.show_inline_completions_override = show_edit_predictions;
 2651        self.update_edit_prediction_settings(cx);
 2652
 2653        if let Some(false) = show_edit_predictions {
 2654            self.discard_inline_completion(false, cx);
 2655        } else {
 2656            self.refresh_inline_completion(false, true, window, cx);
 2657        }
 2658    }
 2659
 2660    fn inline_completions_disabled_in_scope(
 2661        &self,
 2662        buffer: &Entity<Buffer>,
 2663        buffer_position: language::Anchor,
 2664        cx: &App,
 2665    ) -> bool {
 2666        let snapshot = buffer.read(cx).snapshot();
 2667        let settings = snapshot.settings_at(buffer_position, cx);
 2668
 2669        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2670            return false;
 2671        };
 2672
 2673        scope.override_name().map_or(false, |scope_name| {
 2674            settings
 2675                .edit_predictions_disabled_in
 2676                .iter()
 2677                .any(|s| s == scope_name)
 2678        })
 2679    }
 2680
 2681    pub fn set_use_modal_editing(&mut self, to: bool) {
 2682        self.use_modal_editing = to;
 2683    }
 2684
 2685    pub fn use_modal_editing(&self) -> bool {
 2686        self.use_modal_editing
 2687    }
 2688
 2689    fn selections_did_change(
 2690        &mut self,
 2691        local: bool,
 2692        old_cursor_position: &Anchor,
 2693        should_update_completions: bool,
 2694        window: &mut Window,
 2695        cx: &mut Context<Self>,
 2696    ) {
 2697        window.invalidate_character_coordinates();
 2698
 2699        // Copy selections to primary selection buffer
 2700        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2701        if local {
 2702            let selections = self.selections.all::<usize>(cx);
 2703            let buffer_handle = self.buffer.read(cx).read(cx);
 2704
 2705            let mut text = String::new();
 2706            for (index, selection) in selections.iter().enumerate() {
 2707                let text_for_selection = buffer_handle
 2708                    .text_for_range(selection.start..selection.end)
 2709                    .collect::<String>();
 2710
 2711                text.push_str(&text_for_selection);
 2712                if index != selections.len() - 1 {
 2713                    text.push('\n');
 2714                }
 2715            }
 2716
 2717            if !text.is_empty() {
 2718                cx.write_to_primary(ClipboardItem::new_string(text));
 2719            }
 2720        }
 2721
 2722        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2723            self.buffer.update(cx, |buffer, cx| {
 2724                buffer.set_active_selections(
 2725                    &self.selections.disjoint_anchors(),
 2726                    self.selections.line_mode,
 2727                    self.cursor_shape,
 2728                    cx,
 2729                )
 2730            });
 2731        }
 2732        let display_map = self
 2733            .display_map
 2734            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2735        let buffer = &display_map.buffer_snapshot;
 2736        if self.selections.count() == 1 {
 2737            self.add_selections_state = None;
 2738        }
 2739        self.select_next_state = None;
 2740        self.select_prev_state = None;
 2741        self.select_syntax_node_history.try_clear();
 2742        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2743        self.snippet_stack
 2744            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2745        self.take_rename(false, window, cx);
 2746
 2747        let newest_selection = self.selections.newest_anchor();
 2748        let new_cursor_position = newest_selection.head();
 2749        let selection_start = newest_selection.start;
 2750
 2751        self.push_to_nav_history(
 2752            *old_cursor_position,
 2753            Some(new_cursor_position.to_point(buffer)),
 2754            false,
 2755            cx,
 2756        );
 2757
 2758        if local {
 2759            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2760                if !self.registered_buffers.contains_key(&buffer_id) {
 2761                    if let Some(project) = self.project.as_ref() {
 2762                        project.update(cx, |project, cx| {
 2763                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2764                                return;
 2765                            };
 2766                            self.registered_buffers.insert(
 2767                                buffer_id,
 2768                                project.register_buffer_with_language_servers(&buffer, cx),
 2769                            );
 2770                        })
 2771                    }
 2772                }
 2773            }
 2774
 2775            let mut context_menu = self.context_menu.borrow_mut();
 2776            let completion_menu = match context_menu.as_ref() {
 2777                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2778                Some(CodeContextMenu::CodeActions(_)) => {
 2779                    *context_menu = None;
 2780                    None
 2781                }
 2782                None => None,
 2783            };
 2784            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2785            drop(context_menu);
 2786
 2787            if should_update_completions {
 2788                if let Some(completion_position) = completion_position {
 2789                    let start_offset = selection_start.to_offset(buffer);
 2790                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2791                    let continue_showing = if position_matches {
 2792                        if self.snippet_stack.is_empty() {
 2793                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2794                        } else {
 2795                            // Snippet choices can be shown even when the cursor is in whitespace.
 2796                            // Dismissing the menu when actions like backspace
 2797                            true
 2798                        }
 2799                    } else {
 2800                        false
 2801                    };
 2802
 2803                    if continue_showing {
 2804                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2805                    } else {
 2806                        self.hide_context_menu(window, cx);
 2807                    }
 2808                }
 2809            }
 2810
 2811            hide_hover(self, cx);
 2812
 2813            if old_cursor_position.to_display_point(&display_map).row()
 2814                != new_cursor_position.to_display_point(&display_map).row()
 2815            {
 2816                self.available_code_actions.take();
 2817            }
 2818            self.refresh_code_actions(window, cx);
 2819            self.refresh_document_highlights(cx);
 2820            self.refresh_selected_text_highlights(false, window, cx);
 2821            refresh_matching_bracket_highlights(self, window, cx);
 2822            self.update_visible_inline_completion(window, cx);
 2823            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2824            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2825            self.inline_blame_popover.take();
 2826            if self.git_blame_inline_enabled {
 2827                self.start_inline_blame_timer(window, cx);
 2828            }
 2829        }
 2830
 2831        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2832        cx.emit(EditorEvent::SelectionsChanged { local });
 2833
 2834        let selections = &self.selections.disjoint;
 2835        if selections.len() == 1 {
 2836            cx.emit(SearchEvent::ActiveMatchChanged)
 2837        }
 2838        if local {
 2839            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2840                let inmemory_selections = selections
 2841                    .iter()
 2842                    .map(|s| {
 2843                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2844                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2845                    })
 2846                    .collect();
 2847                self.update_restoration_data(cx, |data| {
 2848                    data.selections = inmemory_selections;
 2849                });
 2850
 2851                if WorkspaceSettings::get(None, cx).restore_on_startup
 2852                    != RestoreOnStartupBehavior::None
 2853                {
 2854                    if let Some(workspace_id) =
 2855                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2856                    {
 2857                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2858                        let selections = selections.clone();
 2859                        let background_executor = cx.background_executor().clone();
 2860                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2861                        self.serialize_selections = cx.background_spawn(async move {
 2862                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2863                    let db_selections = selections
 2864                        .iter()
 2865                        .map(|selection| {
 2866                            (
 2867                                selection.start.to_offset(&snapshot),
 2868                                selection.end.to_offset(&snapshot),
 2869                            )
 2870                        })
 2871                        .collect();
 2872
 2873                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2874                        .await
 2875                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2876                        .log_err();
 2877                });
 2878                    }
 2879                }
 2880            }
 2881        }
 2882
 2883        cx.notify();
 2884    }
 2885
 2886    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2887        use text::ToOffset as _;
 2888        use text::ToPoint as _;
 2889
 2890        if self.mode.is_minimap()
 2891            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2892        {
 2893            return;
 2894        }
 2895
 2896        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2897            return;
 2898        };
 2899
 2900        let snapshot = singleton.read(cx).snapshot();
 2901        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2902            let display_snapshot = display_map.snapshot(cx);
 2903
 2904            display_snapshot
 2905                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2906                .map(|fold| {
 2907                    fold.range.start.text_anchor.to_point(&snapshot)
 2908                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2909                })
 2910                .collect()
 2911        });
 2912        self.update_restoration_data(cx, |data| {
 2913            data.folds = inmemory_folds;
 2914        });
 2915
 2916        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2917            return;
 2918        };
 2919        let background_executor = cx.background_executor().clone();
 2920        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2921        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2922            display_map
 2923                .snapshot(cx)
 2924                .folds_in_range(0..snapshot.len())
 2925                .map(|fold| {
 2926                    (
 2927                        fold.range.start.text_anchor.to_offset(&snapshot),
 2928                        fold.range.end.text_anchor.to_offset(&snapshot),
 2929                    )
 2930                })
 2931                .collect()
 2932        });
 2933        self.serialize_folds = cx.background_spawn(async move {
 2934            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2935            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2936                .await
 2937                .with_context(|| {
 2938                    format!(
 2939                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2940                    )
 2941                })
 2942                .log_err();
 2943        });
 2944    }
 2945
 2946    pub fn sync_selections(
 2947        &mut self,
 2948        other: Entity<Editor>,
 2949        cx: &mut Context<Self>,
 2950    ) -> gpui::Subscription {
 2951        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2952        self.selections.change_with(cx, |selections| {
 2953            selections.select_anchors(other_selections);
 2954        });
 2955
 2956        let other_subscription =
 2957            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2958                EditorEvent::SelectionsChanged { local: true } => {
 2959                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2960                    if other_selections.is_empty() {
 2961                        return;
 2962                    }
 2963                    this.selections.change_with(cx, |selections| {
 2964                        selections.select_anchors(other_selections);
 2965                    });
 2966                }
 2967                _ => {}
 2968            });
 2969
 2970        let this_subscription =
 2971            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2972                EditorEvent::SelectionsChanged { local: true } => {
 2973                    let these_selections = this.selections.disjoint.to_vec();
 2974                    if these_selections.is_empty() {
 2975                        return;
 2976                    }
 2977                    other.update(cx, |other_editor, cx| {
 2978                        other_editor.selections.change_with(cx, |selections| {
 2979                            selections.select_anchors(these_selections);
 2980                        })
 2981                    });
 2982                }
 2983                _ => {}
 2984            });
 2985
 2986        Subscription::join(other_subscription, this_subscription)
 2987    }
 2988
 2989    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2990    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2991    /// effects of selection change occur at the end of the transaction.
 2992    pub fn change_selections<R>(
 2993        &mut self,
 2994        autoscroll: Option<Autoscroll>,
 2995        window: &mut Window,
 2996        cx: &mut Context<Self>,
 2997        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2998    ) -> R {
 2999        self.change_selections_inner(true, autoscroll, window, cx, change)
 3000    }
 3001
 3002    pub(crate) fn change_selections_without_updating_completions<R>(
 3003        &mut self,
 3004        autoscroll: Option<Autoscroll>,
 3005        window: &mut Window,
 3006        cx: &mut Context<Self>,
 3007        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3008    ) -> R {
 3009        self.change_selections_inner(false, autoscroll, window, cx, change)
 3010    }
 3011
 3012    fn change_selections_inner<R>(
 3013        &mut self,
 3014        should_update_completions: bool,
 3015        autoscroll: Option<Autoscroll>,
 3016        window: &mut Window,
 3017        cx: &mut Context<Self>,
 3018        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3019    ) -> R {
 3020        if let Some(state) = &mut self.deferred_selection_effects_state {
 3021            state.autoscroll = autoscroll.or(state.autoscroll);
 3022            state.should_update_completions = should_update_completions;
 3023            let (changed, result) = self.selections.change_with(cx, change);
 3024            state.changed |= changed;
 3025            return result;
 3026        }
 3027        let mut state = DeferredSelectionEffectsState {
 3028            changed: false,
 3029            should_update_completions,
 3030            autoscroll,
 3031            old_cursor_position: self.selections.newest_anchor().head(),
 3032            history_entry: SelectionHistoryEntry {
 3033                selections: self.selections.disjoint_anchors(),
 3034                select_next_state: self.select_next_state.clone(),
 3035                select_prev_state: self.select_prev_state.clone(),
 3036                add_selections_state: self.add_selections_state.clone(),
 3037            },
 3038        };
 3039        let (changed, result) = self.selections.change_with(cx, change);
 3040        state.changed = state.changed || changed;
 3041        if self.defer_selection_effects {
 3042            self.deferred_selection_effects_state = Some(state);
 3043        } else {
 3044            self.apply_selection_effects(state, window, cx);
 3045        }
 3046        result
 3047    }
 3048
 3049    /// Defers the effects of selection change, so that the effects of multiple calls to
 3050    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3051    /// to selection history and the state of popovers based on selection position aren't
 3052    /// erroneously updated.
 3053    pub fn with_selection_effects_deferred<R>(
 3054        &mut self,
 3055        window: &mut Window,
 3056        cx: &mut Context<Self>,
 3057        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3058    ) -> R {
 3059        let already_deferred = self.defer_selection_effects;
 3060        self.defer_selection_effects = true;
 3061        let result = update(self, window, cx);
 3062        if !already_deferred {
 3063            self.defer_selection_effects = false;
 3064            if let Some(state) = self.deferred_selection_effects_state.take() {
 3065                self.apply_selection_effects(state, window, cx);
 3066            }
 3067        }
 3068        result
 3069    }
 3070
 3071    fn apply_selection_effects(
 3072        &mut self,
 3073        state: DeferredSelectionEffectsState,
 3074        window: &mut Window,
 3075        cx: &mut Context<Self>,
 3076    ) {
 3077        if state.changed {
 3078            self.selection_history.push(state.history_entry);
 3079
 3080            if let Some(autoscroll) = state.autoscroll {
 3081                self.request_autoscroll(autoscroll, cx);
 3082            }
 3083
 3084            let old_cursor_position = &state.old_cursor_position;
 3085
 3086            self.selections_did_change(
 3087                true,
 3088                &old_cursor_position,
 3089                state.should_update_completions,
 3090                window,
 3091                cx,
 3092            );
 3093
 3094            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3095                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3096            }
 3097        }
 3098    }
 3099
 3100    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3101    where
 3102        I: IntoIterator<Item = (Range<S>, T)>,
 3103        S: ToOffset,
 3104        T: Into<Arc<str>>,
 3105    {
 3106        if self.read_only(cx) {
 3107            return;
 3108        }
 3109
 3110        self.buffer
 3111            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3112    }
 3113
 3114    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3115    where
 3116        I: IntoIterator<Item = (Range<S>, T)>,
 3117        S: ToOffset,
 3118        T: Into<Arc<str>>,
 3119    {
 3120        if self.read_only(cx) {
 3121            return;
 3122        }
 3123
 3124        self.buffer.update(cx, |buffer, cx| {
 3125            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3126        });
 3127    }
 3128
 3129    pub fn edit_with_block_indent<I, S, T>(
 3130        &mut self,
 3131        edits: I,
 3132        original_indent_columns: Vec<Option<u32>>,
 3133        cx: &mut Context<Self>,
 3134    ) where
 3135        I: IntoIterator<Item = (Range<S>, T)>,
 3136        S: ToOffset,
 3137        T: Into<Arc<str>>,
 3138    {
 3139        if self.read_only(cx) {
 3140            return;
 3141        }
 3142
 3143        self.buffer.update(cx, |buffer, cx| {
 3144            buffer.edit(
 3145                edits,
 3146                Some(AutoindentMode::Block {
 3147                    original_indent_columns,
 3148                }),
 3149                cx,
 3150            )
 3151        });
 3152    }
 3153
 3154    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3155        self.hide_context_menu(window, cx);
 3156
 3157        match phase {
 3158            SelectPhase::Begin {
 3159                position,
 3160                add,
 3161                click_count,
 3162            } => self.begin_selection(position, add, click_count, window, cx),
 3163            SelectPhase::BeginColumnar {
 3164                position,
 3165                goal_column,
 3166                reset,
 3167            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3168            SelectPhase::Extend {
 3169                position,
 3170                click_count,
 3171            } => self.extend_selection(position, click_count, window, cx),
 3172            SelectPhase::Update {
 3173                position,
 3174                goal_column,
 3175                scroll_delta,
 3176            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3177            SelectPhase::End => self.end_selection(window, cx),
 3178        }
 3179    }
 3180
 3181    fn extend_selection(
 3182        &mut self,
 3183        position: DisplayPoint,
 3184        click_count: usize,
 3185        window: &mut Window,
 3186        cx: &mut Context<Self>,
 3187    ) {
 3188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3189        let tail = self.selections.newest::<usize>(cx).tail();
 3190        self.begin_selection(position, false, click_count, window, cx);
 3191
 3192        let position = position.to_offset(&display_map, Bias::Left);
 3193        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3194
 3195        let mut pending_selection = self
 3196            .selections
 3197            .pending_anchor()
 3198            .expect("extend_selection not called with pending selection");
 3199        if position >= tail {
 3200            pending_selection.start = tail_anchor;
 3201        } else {
 3202            pending_selection.end = tail_anchor;
 3203            pending_selection.reversed = true;
 3204        }
 3205
 3206        let mut pending_mode = self.selections.pending_mode().unwrap();
 3207        match &mut pending_mode {
 3208            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3209            _ => {}
 3210        }
 3211
 3212        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3213
 3214        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3215            s.set_pending(pending_selection, pending_mode)
 3216        });
 3217    }
 3218
 3219    fn begin_selection(
 3220        &mut self,
 3221        position: DisplayPoint,
 3222        add: bool,
 3223        click_count: usize,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226    ) {
 3227        if !self.focus_handle.is_focused(window) {
 3228            self.last_focused_descendant = None;
 3229            window.focus(&self.focus_handle);
 3230        }
 3231
 3232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3233        let buffer = &display_map.buffer_snapshot;
 3234        let position = display_map.clip_point(position, Bias::Left);
 3235
 3236        let start;
 3237        let end;
 3238        let mode;
 3239        let mut auto_scroll;
 3240        match click_count {
 3241            1 => {
 3242                start = buffer.anchor_before(position.to_point(&display_map));
 3243                end = start;
 3244                mode = SelectMode::Character;
 3245                auto_scroll = true;
 3246            }
 3247            2 => {
 3248                let range = movement::surrounding_word(&display_map, position);
 3249                start = buffer.anchor_before(range.start.to_point(&display_map));
 3250                end = buffer.anchor_before(range.end.to_point(&display_map));
 3251                mode = SelectMode::Word(start..end);
 3252                auto_scroll = true;
 3253            }
 3254            3 => {
 3255                let position = display_map
 3256                    .clip_point(position, Bias::Left)
 3257                    .to_point(&display_map);
 3258                let line_start = display_map.prev_line_boundary(position).0;
 3259                let next_line_start = buffer.clip_point(
 3260                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3261                    Bias::Left,
 3262                );
 3263                start = buffer.anchor_before(line_start);
 3264                end = buffer.anchor_before(next_line_start);
 3265                mode = SelectMode::Line(start..end);
 3266                auto_scroll = true;
 3267            }
 3268            _ => {
 3269                start = buffer.anchor_before(0);
 3270                end = buffer.anchor_before(buffer.len());
 3271                mode = SelectMode::All;
 3272                auto_scroll = false;
 3273            }
 3274        }
 3275        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3276
 3277        let point_to_delete: Option<usize> = {
 3278            let selected_points: Vec<Selection<Point>> =
 3279                self.selections.disjoint_in_range(start..end, cx);
 3280
 3281            if !add || click_count > 1 {
 3282                None
 3283            } else if !selected_points.is_empty() {
 3284                Some(selected_points[0].id)
 3285            } else {
 3286                let clicked_point_already_selected =
 3287                    self.selections.disjoint.iter().find(|selection| {
 3288                        selection.start.to_point(buffer) == start.to_point(buffer)
 3289                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3290                    });
 3291
 3292                clicked_point_already_selected.map(|selection| selection.id)
 3293            }
 3294        };
 3295
 3296        let selections_count = self.selections.count();
 3297
 3298        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3299            if let Some(point_to_delete) = point_to_delete {
 3300                s.delete(point_to_delete);
 3301
 3302                if selections_count == 1 {
 3303                    s.set_pending_anchor_range(start..end, mode);
 3304                }
 3305            } else {
 3306                if !add {
 3307                    s.clear_disjoint();
 3308                }
 3309
 3310                s.set_pending_anchor_range(start..end, mode);
 3311            }
 3312        });
 3313    }
 3314
 3315    fn begin_columnar_selection(
 3316        &mut self,
 3317        position: DisplayPoint,
 3318        goal_column: u32,
 3319        reset: bool,
 3320        window: &mut Window,
 3321        cx: &mut Context<Self>,
 3322    ) {
 3323        if !self.focus_handle.is_focused(window) {
 3324            self.last_focused_descendant = None;
 3325            window.focus(&self.focus_handle);
 3326        }
 3327
 3328        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3329
 3330        if reset {
 3331            let pointer_position = display_map
 3332                .buffer_snapshot
 3333                .anchor_before(position.to_point(&display_map));
 3334
 3335            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3336                s.clear_disjoint();
 3337                s.set_pending_anchor_range(
 3338                    pointer_position..pointer_position,
 3339                    SelectMode::Character,
 3340                );
 3341            });
 3342            if position.column() != goal_column {
 3343                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3344            } else {
 3345                self.columnar_display_point = None;
 3346            }
 3347        }
 3348
 3349        let tail = self.selections.newest::<Point>(cx).tail();
 3350        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3351
 3352        if !reset {
 3353            self.columnar_display_point = None;
 3354            self.select_columns(
 3355                tail.to_display_point(&display_map),
 3356                position,
 3357                goal_column,
 3358                &display_map,
 3359                window,
 3360                cx,
 3361            );
 3362        }
 3363    }
 3364
 3365    fn update_selection(
 3366        &mut self,
 3367        position: DisplayPoint,
 3368        goal_column: u32,
 3369        scroll_delta: gpui::Point<f32>,
 3370        window: &mut Window,
 3371        cx: &mut Context<Self>,
 3372    ) {
 3373        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3374
 3375        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3376            let tail = self
 3377                .columnar_display_point
 3378                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3379            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3380        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3381            let buffer = self.buffer.read(cx).snapshot(cx);
 3382            let head;
 3383            let tail;
 3384            let mode = self.selections.pending_mode().unwrap();
 3385            match &mode {
 3386                SelectMode::Character => {
 3387                    head = position.to_point(&display_map);
 3388                    tail = pending.tail().to_point(&buffer);
 3389                }
 3390                SelectMode::Word(original_range) => {
 3391                    let original_display_range = original_range.start.to_display_point(&display_map)
 3392                        ..original_range.end.to_display_point(&display_map);
 3393                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3394                        ..original_display_range.end.to_point(&display_map);
 3395                    if movement::is_inside_word(&display_map, position)
 3396                        || original_display_range.contains(&position)
 3397                    {
 3398                        let word_range = movement::surrounding_word(&display_map, position);
 3399                        if word_range.start < original_display_range.start {
 3400                            head = word_range.start.to_point(&display_map);
 3401                        } else {
 3402                            head = word_range.end.to_point(&display_map);
 3403                        }
 3404                    } else {
 3405                        head = position.to_point(&display_map);
 3406                    }
 3407
 3408                    if head <= original_buffer_range.start {
 3409                        tail = original_buffer_range.end;
 3410                    } else {
 3411                        tail = original_buffer_range.start;
 3412                    }
 3413                }
 3414                SelectMode::Line(original_range) => {
 3415                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3416
 3417                    let position = display_map
 3418                        .clip_point(position, Bias::Left)
 3419                        .to_point(&display_map);
 3420                    let line_start = display_map.prev_line_boundary(position).0;
 3421                    let next_line_start = buffer.clip_point(
 3422                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3423                        Bias::Left,
 3424                    );
 3425
 3426                    if line_start < original_range.start {
 3427                        head = line_start
 3428                    } else {
 3429                        head = next_line_start
 3430                    }
 3431
 3432                    if head <= original_range.start {
 3433                        tail = original_range.end;
 3434                    } else {
 3435                        tail = original_range.start;
 3436                    }
 3437                }
 3438                SelectMode::All => {
 3439                    return;
 3440                }
 3441            };
 3442
 3443            if head < tail {
 3444                pending.start = buffer.anchor_before(head);
 3445                pending.end = buffer.anchor_before(tail);
 3446                pending.reversed = true;
 3447            } else {
 3448                pending.start = buffer.anchor_before(tail);
 3449                pending.end = buffer.anchor_before(head);
 3450                pending.reversed = false;
 3451            }
 3452
 3453            self.change_selections(None, window, cx, |s| {
 3454                s.set_pending(pending, mode);
 3455            });
 3456        } else {
 3457            log::error!("update_selection dispatched with no pending selection");
 3458            return;
 3459        }
 3460
 3461        self.apply_scroll_delta(scroll_delta, window, cx);
 3462        cx.notify();
 3463    }
 3464
 3465    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3466        self.columnar_selection_tail.take();
 3467        if self.selections.pending_anchor().is_some() {
 3468            let selections = self.selections.all::<usize>(cx);
 3469            self.change_selections(None, window, cx, |s| {
 3470                s.select(selections);
 3471                s.clear_pending();
 3472            });
 3473        }
 3474    }
 3475
 3476    fn select_columns(
 3477        &mut self,
 3478        tail: DisplayPoint,
 3479        head: DisplayPoint,
 3480        goal_column: u32,
 3481        display_map: &DisplaySnapshot,
 3482        window: &mut Window,
 3483        cx: &mut Context<Self>,
 3484    ) {
 3485        let start_row = cmp::min(tail.row(), head.row());
 3486        let end_row = cmp::max(tail.row(), head.row());
 3487        let start_column = cmp::min(tail.column(), goal_column);
 3488        let end_column = cmp::max(tail.column(), goal_column);
 3489        let reversed = start_column < tail.column();
 3490
 3491        let selection_ranges = (start_row.0..=end_row.0)
 3492            .map(DisplayRow)
 3493            .filter_map(|row| {
 3494                if !display_map.is_block_line(row) {
 3495                    let start = display_map
 3496                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3497                        .to_point(display_map);
 3498                    let end = display_map
 3499                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3500                        .to_point(display_map);
 3501                    if reversed {
 3502                        Some(end..start)
 3503                    } else {
 3504                        Some(start..end)
 3505                    }
 3506                } else {
 3507                    None
 3508                }
 3509            })
 3510            .collect::<Vec<_>>();
 3511
 3512        let mut non_empty_ranges = selection_ranges
 3513            .iter()
 3514            .filter(|selection_range| selection_range.start != selection_range.end)
 3515            .peekable();
 3516
 3517        let ranges = if non_empty_ranges.peek().is_some() {
 3518            non_empty_ranges.cloned().collect()
 3519        } else {
 3520            selection_ranges
 3521        };
 3522
 3523        self.change_selections(None, window, cx, |s| {
 3524            s.select_ranges(ranges);
 3525        });
 3526        cx.notify();
 3527    }
 3528
 3529    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3530        self.selections
 3531            .all_adjusted(cx)
 3532            .iter()
 3533            .any(|selection| !selection.is_empty())
 3534    }
 3535
 3536    pub fn has_pending_nonempty_selection(&self) -> bool {
 3537        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3538            Some(Selection { start, end, .. }) => start != end,
 3539            None => false,
 3540        };
 3541
 3542        pending_nonempty_selection
 3543            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3544    }
 3545
 3546    pub fn has_pending_selection(&self) -> bool {
 3547        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3548    }
 3549
 3550    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3551        self.selection_mark_mode = false;
 3552        self.selection_drag_state = SelectionDragState::None;
 3553
 3554        if self.clear_expanded_diff_hunks(cx) {
 3555            cx.notify();
 3556            return;
 3557        }
 3558        if self.dismiss_menus_and_popups(true, window, cx) {
 3559            return;
 3560        }
 3561
 3562        if self.mode.is_full()
 3563            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3564        {
 3565            return;
 3566        }
 3567
 3568        cx.propagate();
 3569    }
 3570
 3571    pub fn dismiss_menus_and_popups(
 3572        &mut self,
 3573        is_user_requested: bool,
 3574        window: &mut Window,
 3575        cx: &mut Context<Self>,
 3576    ) -> bool {
 3577        if self.take_rename(false, window, cx).is_some() {
 3578            return true;
 3579        }
 3580
 3581        if hide_hover(self, cx) {
 3582            return true;
 3583        }
 3584
 3585        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3586            return true;
 3587        }
 3588
 3589        if self.hide_context_menu(window, cx).is_some() {
 3590            return true;
 3591        }
 3592
 3593        if self.mouse_context_menu.take().is_some() {
 3594            return true;
 3595        }
 3596
 3597        if is_user_requested && self.discard_inline_completion(true, cx) {
 3598            return true;
 3599        }
 3600
 3601        if self.snippet_stack.pop().is_some() {
 3602            return true;
 3603        }
 3604
 3605        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3606            self.dismiss_diagnostics(cx);
 3607            return true;
 3608        }
 3609
 3610        false
 3611    }
 3612
 3613    fn linked_editing_ranges_for(
 3614        &self,
 3615        selection: Range<text::Anchor>,
 3616        cx: &App,
 3617    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3618        if self.linked_edit_ranges.is_empty() {
 3619            return None;
 3620        }
 3621        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3622            selection.end.buffer_id.and_then(|end_buffer_id| {
 3623                if selection.start.buffer_id != Some(end_buffer_id) {
 3624                    return None;
 3625                }
 3626                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3627                let snapshot = buffer.read(cx).snapshot();
 3628                self.linked_edit_ranges
 3629                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3630                    .map(|ranges| (ranges, snapshot, buffer))
 3631            })?;
 3632        use text::ToOffset as TO;
 3633        // find offset from the start of current range to current cursor position
 3634        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3635
 3636        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3637        let start_difference = start_offset - start_byte_offset;
 3638        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3639        let end_difference = end_offset - start_byte_offset;
 3640        // Current range has associated linked ranges.
 3641        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3642        for range in linked_ranges.iter() {
 3643            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3644            let end_offset = start_offset + end_difference;
 3645            let start_offset = start_offset + start_difference;
 3646            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3647                continue;
 3648            }
 3649            if self.selections.disjoint_anchor_ranges().any(|s| {
 3650                if s.start.buffer_id != selection.start.buffer_id
 3651                    || s.end.buffer_id != selection.end.buffer_id
 3652                {
 3653                    return false;
 3654                }
 3655                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3656                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3657            }) {
 3658                continue;
 3659            }
 3660            let start = buffer_snapshot.anchor_after(start_offset);
 3661            let end = buffer_snapshot.anchor_after(end_offset);
 3662            linked_edits
 3663                .entry(buffer.clone())
 3664                .or_default()
 3665                .push(start..end);
 3666        }
 3667        Some(linked_edits)
 3668    }
 3669
 3670    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3671        let text: Arc<str> = text.into();
 3672
 3673        if self.read_only(cx) {
 3674            return;
 3675        }
 3676
 3677        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3678
 3679        let selections = self.selections.all_adjusted(cx);
 3680        let mut bracket_inserted = false;
 3681        let mut edits = Vec::new();
 3682        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3683        let mut new_selections = Vec::with_capacity(selections.len());
 3684        let mut new_autoclose_regions = Vec::new();
 3685        let snapshot = self.buffer.read(cx).read(cx);
 3686        let mut clear_linked_edit_ranges = false;
 3687
 3688        for (selection, autoclose_region) in
 3689            self.selections_with_autoclose_regions(selections, &snapshot)
 3690        {
 3691            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3692                // Determine if the inserted text matches the opening or closing
 3693                // bracket of any of this language's bracket pairs.
 3694                let mut bracket_pair = None;
 3695                let mut is_bracket_pair_start = false;
 3696                let mut is_bracket_pair_end = false;
 3697                if !text.is_empty() {
 3698                    let mut bracket_pair_matching_end = None;
 3699                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3700                    //  and they are removing the character that triggered IME popup.
 3701                    for (pair, enabled) in scope.brackets() {
 3702                        if !pair.close && !pair.surround {
 3703                            continue;
 3704                        }
 3705
 3706                        if enabled && pair.start.ends_with(text.as_ref()) {
 3707                            let prefix_len = pair.start.len() - text.len();
 3708                            let preceding_text_matches_prefix = prefix_len == 0
 3709                                || (selection.start.column >= (prefix_len as u32)
 3710                                    && snapshot.contains_str_at(
 3711                                        Point::new(
 3712                                            selection.start.row,
 3713                                            selection.start.column - (prefix_len as u32),
 3714                                        ),
 3715                                        &pair.start[..prefix_len],
 3716                                    ));
 3717                            if preceding_text_matches_prefix {
 3718                                bracket_pair = Some(pair.clone());
 3719                                is_bracket_pair_start = true;
 3720                                break;
 3721                            }
 3722                        }
 3723                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3724                        {
 3725                            // take first bracket pair matching end, but don't break in case a later bracket
 3726                            // pair matches start
 3727                            bracket_pair_matching_end = Some(pair.clone());
 3728                        }
 3729                    }
 3730                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3731                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3732                        is_bracket_pair_end = true;
 3733                    }
 3734                }
 3735
 3736                if let Some(bracket_pair) = bracket_pair {
 3737                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3738                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3739                    let auto_surround =
 3740                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3741                    if selection.is_empty() {
 3742                        if is_bracket_pair_start {
 3743                            // If the inserted text is a suffix of an opening bracket and the
 3744                            // selection is preceded by the rest of the opening bracket, then
 3745                            // insert the closing bracket.
 3746                            let following_text_allows_autoclose = snapshot
 3747                                .chars_at(selection.start)
 3748                                .next()
 3749                                .map_or(true, |c| scope.should_autoclose_before(c));
 3750
 3751                            let preceding_text_allows_autoclose = selection.start.column == 0
 3752                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3753                                    true,
 3754                                    |c| {
 3755                                        bracket_pair.start != bracket_pair.end
 3756                                            || !snapshot
 3757                                                .char_classifier_at(selection.start)
 3758                                                .is_word(c)
 3759                                    },
 3760                                );
 3761
 3762                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3763                                && bracket_pair.start.len() == 1
 3764                            {
 3765                                let target = bracket_pair.start.chars().next().unwrap();
 3766                                let current_line_count = snapshot
 3767                                    .reversed_chars_at(selection.start)
 3768                                    .take_while(|&c| c != '\n')
 3769                                    .filter(|&c| c == target)
 3770                                    .count();
 3771                                current_line_count % 2 == 1
 3772                            } else {
 3773                                false
 3774                            };
 3775
 3776                            if autoclose
 3777                                && bracket_pair.close
 3778                                && following_text_allows_autoclose
 3779                                && preceding_text_allows_autoclose
 3780                                && !is_closing_quote
 3781                            {
 3782                                let anchor = snapshot.anchor_before(selection.end);
 3783                                new_selections.push((selection.map(|_| anchor), text.len()));
 3784                                new_autoclose_regions.push((
 3785                                    anchor,
 3786                                    text.len(),
 3787                                    selection.id,
 3788                                    bracket_pair.clone(),
 3789                                ));
 3790                                edits.push((
 3791                                    selection.range(),
 3792                                    format!("{}{}", text, bracket_pair.end).into(),
 3793                                ));
 3794                                bracket_inserted = true;
 3795                                continue;
 3796                            }
 3797                        }
 3798
 3799                        if let Some(region) = autoclose_region {
 3800                            // If the selection is followed by an auto-inserted closing bracket,
 3801                            // then don't insert that closing bracket again; just move the selection
 3802                            // past the closing bracket.
 3803                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3804                                && text.as_ref() == region.pair.end.as_str();
 3805                            if should_skip {
 3806                                let anchor = snapshot.anchor_after(selection.end);
 3807                                new_selections
 3808                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3809                                continue;
 3810                            }
 3811                        }
 3812
 3813                        let always_treat_brackets_as_autoclosed = snapshot
 3814                            .language_settings_at(selection.start, cx)
 3815                            .always_treat_brackets_as_autoclosed;
 3816                        if always_treat_brackets_as_autoclosed
 3817                            && is_bracket_pair_end
 3818                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3819                        {
 3820                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3821                            // and the inserted text is a closing bracket and the selection is followed
 3822                            // by the closing bracket then move the selection past the closing bracket.
 3823                            let anchor = snapshot.anchor_after(selection.end);
 3824                            new_selections.push((selection.map(|_| anchor), text.len()));
 3825                            continue;
 3826                        }
 3827                    }
 3828                    // If an opening bracket is 1 character long and is typed while
 3829                    // text is selected, then surround that text with the bracket pair.
 3830                    else if auto_surround
 3831                        && bracket_pair.surround
 3832                        && is_bracket_pair_start
 3833                        && bracket_pair.start.chars().count() == 1
 3834                    {
 3835                        edits.push((selection.start..selection.start, text.clone()));
 3836                        edits.push((
 3837                            selection.end..selection.end,
 3838                            bracket_pair.end.as_str().into(),
 3839                        ));
 3840                        bracket_inserted = true;
 3841                        new_selections.push((
 3842                            Selection {
 3843                                id: selection.id,
 3844                                start: snapshot.anchor_after(selection.start),
 3845                                end: snapshot.anchor_before(selection.end),
 3846                                reversed: selection.reversed,
 3847                                goal: selection.goal,
 3848                            },
 3849                            0,
 3850                        ));
 3851                        continue;
 3852                    }
 3853                }
 3854            }
 3855
 3856            if self.auto_replace_emoji_shortcode
 3857                && selection.is_empty()
 3858                && text.as_ref().ends_with(':')
 3859            {
 3860                if let Some(possible_emoji_short_code) =
 3861                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3862                {
 3863                    if !possible_emoji_short_code.is_empty() {
 3864                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3865                            let emoji_shortcode_start = Point::new(
 3866                                selection.start.row,
 3867                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3868                            );
 3869
 3870                            // Remove shortcode from buffer
 3871                            edits.push((
 3872                                emoji_shortcode_start..selection.start,
 3873                                "".to_string().into(),
 3874                            ));
 3875                            new_selections.push((
 3876                                Selection {
 3877                                    id: selection.id,
 3878                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3879                                    end: snapshot.anchor_before(selection.start),
 3880                                    reversed: selection.reversed,
 3881                                    goal: selection.goal,
 3882                                },
 3883                                0,
 3884                            ));
 3885
 3886                            // Insert emoji
 3887                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3888                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3889                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3890
 3891                            continue;
 3892                        }
 3893                    }
 3894                }
 3895            }
 3896
 3897            // If not handling any auto-close operation, then just replace the selected
 3898            // text with the given input and move the selection to the end of the
 3899            // newly inserted text.
 3900            let anchor = snapshot.anchor_after(selection.end);
 3901            if !self.linked_edit_ranges.is_empty() {
 3902                let start_anchor = snapshot.anchor_before(selection.start);
 3903
 3904                let is_word_char = text.chars().next().map_or(true, |char| {
 3905                    let classifier = snapshot
 3906                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3907                        .ignore_punctuation(true);
 3908                    classifier.is_word(char)
 3909                });
 3910
 3911                if is_word_char {
 3912                    if let Some(ranges) = self
 3913                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3914                    {
 3915                        for (buffer, edits) in ranges {
 3916                            linked_edits
 3917                                .entry(buffer.clone())
 3918                                .or_default()
 3919                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3920                        }
 3921                    }
 3922                } else {
 3923                    clear_linked_edit_ranges = true;
 3924                }
 3925            }
 3926
 3927            new_selections.push((selection.map(|_| anchor), 0));
 3928            edits.push((selection.start..selection.end, text.clone()));
 3929        }
 3930
 3931        drop(snapshot);
 3932
 3933        self.transact(window, cx, |this, window, cx| {
 3934            if clear_linked_edit_ranges {
 3935                this.linked_edit_ranges.clear();
 3936            }
 3937            let initial_buffer_versions =
 3938                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3939
 3940            this.buffer.update(cx, |buffer, cx| {
 3941                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3942            });
 3943            for (buffer, edits) in linked_edits {
 3944                buffer.update(cx, |buffer, cx| {
 3945                    let snapshot = buffer.snapshot();
 3946                    let edits = edits
 3947                        .into_iter()
 3948                        .map(|(range, text)| {
 3949                            use text::ToPoint as TP;
 3950                            let end_point = TP::to_point(&range.end, &snapshot);
 3951                            let start_point = TP::to_point(&range.start, &snapshot);
 3952                            (start_point..end_point, text)
 3953                        })
 3954                        .sorted_by_key(|(range, _)| range.start);
 3955                    buffer.edit(edits, None, cx);
 3956                })
 3957            }
 3958            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3959            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3960            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3961            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3962                .zip(new_selection_deltas)
 3963                .map(|(selection, delta)| Selection {
 3964                    id: selection.id,
 3965                    start: selection.start + delta,
 3966                    end: selection.end + delta,
 3967                    reversed: selection.reversed,
 3968                    goal: SelectionGoal::None,
 3969                })
 3970                .collect::<Vec<_>>();
 3971
 3972            let mut i = 0;
 3973            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3974                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3975                let start = map.buffer_snapshot.anchor_before(position);
 3976                let end = map.buffer_snapshot.anchor_after(position);
 3977                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3978                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3979                        Ordering::Less => i += 1,
 3980                        Ordering::Greater => break,
 3981                        Ordering::Equal => {
 3982                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3983                                Ordering::Less => i += 1,
 3984                                Ordering::Equal => break,
 3985                                Ordering::Greater => break,
 3986                            }
 3987                        }
 3988                    }
 3989                }
 3990                this.autoclose_regions.insert(
 3991                    i,
 3992                    AutocloseRegion {
 3993                        selection_id,
 3994                        range: start..end,
 3995                        pair,
 3996                    },
 3997                );
 3998            }
 3999
 4000            let had_active_inline_completion = this.has_active_inline_completion();
 4001            this.change_selections_without_updating_completions(
 4002                Some(Autoscroll::fit()),
 4003                window,
 4004                cx,
 4005                |s| s.select(new_selections),
 4006            );
 4007
 4008            if !bracket_inserted {
 4009                if let Some(on_type_format_task) =
 4010                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4011                {
 4012                    on_type_format_task.detach_and_log_err(cx);
 4013                }
 4014            }
 4015
 4016            let editor_settings = EditorSettings::get_global(cx);
 4017            if bracket_inserted
 4018                && (editor_settings.auto_signature_help
 4019                    || editor_settings.show_signature_help_after_edits)
 4020            {
 4021                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4022            }
 4023
 4024            let trigger_in_words =
 4025                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4026            if this.hard_wrap.is_some() {
 4027                let latest: Range<Point> = this.selections.newest(cx).range();
 4028                if latest.is_empty()
 4029                    && this
 4030                        .buffer()
 4031                        .read(cx)
 4032                        .snapshot(cx)
 4033                        .line_len(MultiBufferRow(latest.start.row))
 4034                        == latest.start.column
 4035                {
 4036                    this.rewrap_impl(
 4037                        RewrapOptions {
 4038                            override_language_settings: true,
 4039                            preserve_existing_whitespace: true,
 4040                        },
 4041                        cx,
 4042                    )
 4043                }
 4044            }
 4045            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4046            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4047            this.refresh_inline_completion(true, false, window, cx);
 4048            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4049        });
 4050    }
 4051
 4052    fn find_possible_emoji_shortcode_at_position(
 4053        snapshot: &MultiBufferSnapshot,
 4054        position: Point,
 4055    ) -> Option<String> {
 4056        let mut chars = Vec::new();
 4057        let mut found_colon = false;
 4058        for char in snapshot.reversed_chars_at(position).take(100) {
 4059            // Found a possible emoji shortcode in the middle of the buffer
 4060            if found_colon {
 4061                if char.is_whitespace() {
 4062                    chars.reverse();
 4063                    return Some(chars.iter().collect());
 4064                }
 4065                // If the previous character is not a whitespace, we are in the middle of a word
 4066                // and we only want to complete the shortcode if the word is made up of other emojis
 4067                let mut containing_word = String::new();
 4068                for ch in snapshot
 4069                    .reversed_chars_at(position)
 4070                    .skip(chars.len() + 1)
 4071                    .take(100)
 4072                {
 4073                    if ch.is_whitespace() {
 4074                        break;
 4075                    }
 4076                    containing_word.push(ch);
 4077                }
 4078                let containing_word = containing_word.chars().rev().collect::<String>();
 4079                if util::word_consists_of_emojis(containing_word.as_str()) {
 4080                    chars.reverse();
 4081                    return Some(chars.iter().collect());
 4082                }
 4083            }
 4084
 4085            if char.is_whitespace() || !char.is_ascii() {
 4086                return None;
 4087            }
 4088            if char == ':' {
 4089                found_colon = true;
 4090            } else {
 4091                chars.push(char);
 4092            }
 4093        }
 4094        // Found a possible emoji shortcode at the beginning of the buffer
 4095        chars.reverse();
 4096        Some(chars.iter().collect())
 4097    }
 4098
 4099    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4100        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4101        self.transact(window, cx, |this, window, cx| {
 4102            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4103                let selections = this.selections.all::<usize>(cx);
 4104                let multi_buffer = this.buffer.read(cx);
 4105                let buffer = multi_buffer.snapshot(cx);
 4106                selections
 4107                    .iter()
 4108                    .map(|selection| {
 4109                        let start_point = selection.start.to_point(&buffer);
 4110                        let mut existing_indent =
 4111                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4112                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4113                        let start = selection.start;
 4114                        let end = selection.end;
 4115                        let selection_is_empty = start == end;
 4116                        let language_scope = buffer.language_scope_at(start);
 4117                        let (
 4118                            comment_delimiter,
 4119                            doc_delimiter,
 4120                            insert_extra_newline,
 4121                            indent_on_newline,
 4122                            indent_on_extra_newline,
 4123                        ) = if let Some(language) = &language_scope {
 4124                            let mut insert_extra_newline =
 4125                                insert_extra_newline_brackets(&buffer, start..end, language)
 4126                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4127
 4128                            // Comment extension on newline is allowed only for cursor selections
 4129                            let comment_delimiter = maybe!({
 4130                                if !selection_is_empty {
 4131                                    return None;
 4132                                }
 4133
 4134                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4135                                    return None;
 4136                                }
 4137
 4138                                let delimiters = language.line_comment_prefixes();
 4139                                let max_len_of_delimiter =
 4140                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4141                                let (snapshot, range) =
 4142                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4143
 4144                                let num_of_whitespaces = snapshot
 4145                                    .chars_for_range(range.clone())
 4146                                    .take_while(|c| c.is_whitespace())
 4147                                    .count();
 4148                                let comment_candidate = snapshot
 4149                                    .chars_for_range(range)
 4150                                    .skip(num_of_whitespaces)
 4151                                    .take(max_len_of_delimiter)
 4152                                    .collect::<String>();
 4153                                let (delimiter, trimmed_len) = delimiters
 4154                                    .iter()
 4155                                    .filter_map(|delimiter| {
 4156                                        let prefix = delimiter.trim_end();
 4157                                        if comment_candidate.starts_with(prefix) {
 4158                                            Some((delimiter, prefix.len()))
 4159                                        } else {
 4160                                            None
 4161                                        }
 4162                                    })
 4163                                    .max_by_key(|(_, len)| *len)?;
 4164
 4165                                let cursor_is_placed_after_comment_marker =
 4166                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4167                                if cursor_is_placed_after_comment_marker {
 4168                                    Some(delimiter.clone())
 4169                                } else {
 4170                                    None
 4171                                }
 4172                            });
 4173
 4174                            let mut indent_on_newline = IndentSize::spaces(0);
 4175                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4176
 4177                            let doc_delimiter = maybe!({
 4178                                if !selection_is_empty {
 4179                                    return None;
 4180                                }
 4181
 4182                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4183                                    return None;
 4184                                }
 4185
 4186                                let DocumentationConfig {
 4187                                    start: start_tag,
 4188                                    end: end_tag,
 4189                                    prefix: delimiter,
 4190                                    tab_size: len,
 4191                                } = language.documentation()?;
 4192
 4193                                let is_within_block_comment = buffer
 4194                                    .language_scope_at(start_point)
 4195                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4196                                if !is_within_block_comment {
 4197                                    return None;
 4198                                }
 4199
 4200                                let (snapshot, range) =
 4201                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4202
 4203                                let num_of_whitespaces = snapshot
 4204                                    .chars_for_range(range.clone())
 4205                                    .take_while(|c| c.is_whitespace())
 4206                                    .count();
 4207
 4208                                // 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.
 4209                                let column = start_point.column;
 4210                                let cursor_is_after_start_tag = {
 4211                                    let start_tag_len = start_tag.len();
 4212                                    let start_tag_line = snapshot
 4213                                        .chars_for_range(range.clone())
 4214                                        .skip(num_of_whitespaces)
 4215                                        .take(start_tag_len)
 4216                                        .collect::<String>();
 4217                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4218                                        num_of_whitespaces + start_tag_len <= column as usize
 4219                                    } else {
 4220                                        false
 4221                                    }
 4222                                };
 4223
 4224                                let cursor_is_after_delimiter = {
 4225                                    let delimiter_trim = delimiter.trim_end();
 4226                                    let delimiter_line = snapshot
 4227                                        .chars_for_range(range.clone())
 4228                                        .skip(num_of_whitespaces)
 4229                                        .take(delimiter_trim.len())
 4230                                        .collect::<String>();
 4231                                    if delimiter_line.starts_with(delimiter_trim) {
 4232                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4233                                    } else {
 4234                                        false
 4235                                    }
 4236                                };
 4237
 4238                                let cursor_is_before_end_tag_if_exists = {
 4239                                    let mut char_position = 0u32;
 4240                                    let mut end_tag_offset = None;
 4241
 4242                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4243                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4244                                            let chars_before_match =
 4245                                                chunk[..byte_pos].chars().count() as u32;
 4246                                            end_tag_offset =
 4247                                                Some(char_position + chars_before_match);
 4248                                            break 'outer;
 4249                                        }
 4250                                        char_position += chunk.chars().count() as u32;
 4251                                    }
 4252
 4253                                    if let Some(end_tag_offset) = end_tag_offset {
 4254                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4255                                        if cursor_is_after_start_tag {
 4256                                            if cursor_is_before_end_tag {
 4257                                                insert_extra_newline = true;
 4258                                            }
 4259                                            let cursor_is_at_start_of_end_tag =
 4260                                                column == end_tag_offset;
 4261                                            if cursor_is_at_start_of_end_tag {
 4262                                                indent_on_extra_newline.len = (*len).into();
 4263                                            }
 4264                                        }
 4265                                        cursor_is_before_end_tag
 4266                                    } else {
 4267                                        true
 4268                                    }
 4269                                };
 4270
 4271                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4272                                    && cursor_is_before_end_tag_if_exists
 4273                                {
 4274                                    if cursor_is_after_start_tag {
 4275                                        indent_on_newline.len = (*len).into();
 4276                                    }
 4277                                    Some(delimiter.clone())
 4278                                } else {
 4279                                    None
 4280                                }
 4281                            });
 4282
 4283                            (
 4284                                comment_delimiter,
 4285                                doc_delimiter,
 4286                                insert_extra_newline,
 4287                                indent_on_newline,
 4288                                indent_on_extra_newline,
 4289                            )
 4290                        } else {
 4291                            (
 4292                                None,
 4293                                None,
 4294                                false,
 4295                                IndentSize::default(),
 4296                                IndentSize::default(),
 4297                            )
 4298                        };
 4299
 4300                        let prevent_auto_indent = doc_delimiter.is_some();
 4301                        let delimiter = comment_delimiter.or(doc_delimiter);
 4302
 4303                        let capacity_for_delimiter =
 4304                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4305                        let mut new_text = String::with_capacity(
 4306                            1 + capacity_for_delimiter
 4307                                + existing_indent.len as usize
 4308                                + indent_on_newline.len as usize
 4309                                + indent_on_extra_newline.len as usize,
 4310                        );
 4311                        new_text.push('\n');
 4312                        new_text.extend(existing_indent.chars());
 4313                        new_text.extend(indent_on_newline.chars());
 4314
 4315                        if let Some(delimiter) = &delimiter {
 4316                            new_text.push_str(delimiter);
 4317                        }
 4318
 4319                        if insert_extra_newline {
 4320                            new_text.push('\n');
 4321                            new_text.extend(existing_indent.chars());
 4322                            new_text.extend(indent_on_extra_newline.chars());
 4323                        }
 4324
 4325                        let anchor = buffer.anchor_after(end);
 4326                        let new_selection = selection.map(|_| anchor);
 4327                        (
 4328                            ((start..end, new_text), prevent_auto_indent),
 4329                            (insert_extra_newline, new_selection),
 4330                        )
 4331                    })
 4332                    .unzip()
 4333            };
 4334
 4335            let mut auto_indent_edits = Vec::new();
 4336            let mut edits = Vec::new();
 4337            for (edit, prevent_auto_indent) in edits_with_flags {
 4338                if prevent_auto_indent {
 4339                    edits.push(edit);
 4340                } else {
 4341                    auto_indent_edits.push(edit);
 4342                }
 4343            }
 4344            if !edits.is_empty() {
 4345                this.edit(edits, cx);
 4346            }
 4347            if !auto_indent_edits.is_empty() {
 4348                this.edit_with_autoindent(auto_indent_edits, cx);
 4349            }
 4350
 4351            let buffer = this.buffer.read(cx).snapshot(cx);
 4352            let new_selections = selection_info
 4353                .into_iter()
 4354                .map(|(extra_newline_inserted, new_selection)| {
 4355                    let mut cursor = new_selection.end.to_point(&buffer);
 4356                    if extra_newline_inserted {
 4357                        cursor.row -= 1;
 4358                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4359                    }
 4360                    new_selection.map(|_| cursor)
 4361                })
 4362                .collect();
 4363
 4364            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4365                s.select(new_selections)
 4366            });
 4367            this.refresh_inline_completion(true, false, window, cx);
 4368        });
 4369    }
 4370
 4371    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4372        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4373
 4374        let buffer = self.buffer.read(cx);
 4375        let snapshot = buffer.snapshot(cx);
 4376
 4377        let mut edits = Vec::new();
 4378        let mut rows = Vec::new();
 4379
 4380        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4381            let cursor = selection.head();
 4382            let row = cursor.row;
 4383
 4384            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4385
 4386            let newline = "\n".to_string();
 4387            edits.push((start_of_line..start_of_line, newline));
 4388
 4389            rows.push(row + rows_inserted as u32);
 4390        }
 4391
 4392        self.transact(window, cx, |editor, window, cx| {
 4393            editor.edit(edits, cx);
 4394
 4395            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4396                let mut index = 0;
 4397                s.move_cursors_with(|map, _, _| {
 4398                    let row = rows[index];
 4399                    index += 1;
 4400
 4401                    let point = Point::new(row, 0);
 4402                    let boundary = map.next_line_boundary(point).1;
 4403                    let clipped = map.clip_point(boundary, Bias::Left);
 4404
 4405                    (clipped, SelectionGoal::None)
 4406                });
 4407            });
 4408
 4409            let mut indent_edits = Vec::new();
 4410            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4411            for row in rows {
 4412                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4413                for (row, indent) in indents {
 4414                    if indent.len == 0 {
 4415                        continue;
 4416                    }
 4417
 4418                    let text = match indent.kind {
 4419                        IndentKind::Space => " ".repeat(indent.len as usize),
 4420                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4421                    };
 4422                    let point = Point::new(row.0, 0);
 4423                    indent_edits.push((point..point, text));
 4424                }
 4425            }
 4426            editor.edit(indent_edits, cx);
 4427        });
 4428    }
 4429
 4430    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4431        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4432
 4433        let buffer = self.buffer.read(cx);
 4434        let snapshot = buffer.snapshot(cx);
 4435
 4436        let mut edits = Vec::new();
 4437        let mut rows = Vec::new();
 4438        let mut rows_inserted = 0;
 4439
 4440        for selection in self.selections.all_adjusted(cx) {
 4441            let cursor = selection.head();
 4442            let row = cursor.row;
 4443
 4444            let point = Point::new(row + 1, 0);
 4445            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4446
 4447            let newline = "\n".to_string();
 4448            edits.push((start_of_line..start_of_line, newline));
 4449
 4450            rows_inserted += 1;
 4451            rows.push(row + rows_inserted);
 4452        }
 4453
 4454        self.transact(window, cx, |editor, window, cx| {
 4455            editor.edit(edits, cx);
 4456
 4457            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4458                let mut index = 0;
 4459                s.move_cursors_with(|map, _, _| {
 4460                    let row = rows[index];
 4461                    index += 1;
 4462
 4463                    let point = Point::new(row, 0);
 4464                    let boundary = map.next_line_boundary(point).1;
 4465                    let clipped = map.clip_point(boundary, Bias::Left);
 4466
 4467                    (clipped, SelectionGoal::None)
 4468                });
 4469            });
 4470
 4471            let mut indent_edits = Vec::new();
 4472            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4473            for row in rows {
 4474                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4475                for (row, indent) in indents {
 4476                    if indent.len == 0 {
 4477                        continue;
 4478                    }
 4479
 4480                    let text = match indent.kind {
 4481                        IndentKind::Space => " ".repeat(indent.len as usize),
 4482                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4483                    };
 4484                    let point = Point::new(row.0, 0);
 4485                    indent_edits.push((point..point, text));
 4486                }
 4487            }
 4488            editor.edit(indent_edits, cx);
 4489        });
 4490    }
 4491
 4492    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4493        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4494            original_indent_columns: Vec::new(),
 4495        });
 4496        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4497    }
 4498
 4499    fn insert_with_autoindent_mode(
 4500        &mut self,
 4501        text: &str,
 4502        autoindent_mode: Option<AutoindentMode>,
 4503        window: &mut Window,
 4504        cx: &mut Context<Self>,
 4505    ) {
 4506        if self.read_only(cx) {
 4507            return;
 4508        }
 4509
 4510        let text: Arc<str> = text.into();
 4511        self.transact(window, cx, |this, window, cx| {
 4512            let old_selections = this.selections.all_adjusted(cx);
 4513            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4514                let anchors = {
 4515                    let snapshot = buffer.read(cx);
 4516                    old_selections
 4517                        .iter()
 4518                        .map(|s| {
 4519                            let anchor = snapshot.anchor_after(s.head());
 4520                            s.map(|_| anchor)
 4521                        })
 4522                        .collect::<Vec<_>>()
 4523                };
 4524                buffer.edit(
 4525                    old_selections
 4526                        .iter()
 4527                        .map(|s| (s.start..s.end, text.clone())),
 4528                    autoindent_mode,
 4529                    cx,
 4530                );
 4531                anchors
 4532            });
 4533
 4534            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4535                s.select_anchors(selection_anchors);
 4536            });
 4537
 4538            cx.notify();
 4539        });
 4540    }
 4541
 4542    fn trigger_completion_on_input(
 4543        &mut self,
 4544        text: &str,
 4545        trigger_in_words: bool,
 4546        window: &mut Window,
 4547        cx: &mut Context<Self>,
 4548    ) {
 4549        let completions_source = self
 4550            .context_menu
 4551            .borrow()
 4552            .as_ref()
 4553            .and_then(|menu| match menu {
 4554                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4555                CodeContextMenu::CodeActions(_) => None,
 4556            });
 4557
 4558        match completions_source {
 4559            Some(CompletionsMenuSource::Words) => {
 4560                self.show_word_completions(&ShowWordCompletions, window, cx)
 4561            }
 4562            Some(CompletionsMenuSource::Normal)
 4563            | Some(CompletionsMenuSource::SnippetChoices)
 4564            | None
 4565                if self.is_completion_trigger(
 4566                    text,
 4567                    trigger_in_words,
 4568                    completions_source.is_some(),
 4569                    cx,
 4570                ) =>
 4571            {
 4572                self.show_completions(
 4573                    &ShowCompletions {
 4574                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4575                    },
 4576                    window,
 4577                    cx,
 4578                )
 4579            }
 4580            _ => {
 4581                self.hide_context_menu(window, cx);
 4582            }
 4583        }
 4584    }
 4585
 4586    fn is_completion_trigger(
 4587        &self,
 4588        text: &str,
 4589        trigger_in_words: bool,
 4590        menu_is_open: bool,
 4591        cx: &mut Context<Self>,
 4592    ) -> bool {
 4593        let position = self.selections.newest_anchor().head();
 4594        let multibuffer = self.buffer.read(cx);
 4595        let Some(buffer) = position
 4596            .buffer_id
 4597            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4598        else {
 4599            return false;
 4600        };
 4601
 4602        if let Some(completion_provider) = &self.completion_provider {
 4603            completion_provider.is_completion_trigger(
 4604                &buffer,
 4605                position.text_anchor,
 4606                text,
 4607                trigger_in_words,
 4608                menu_is_open,
 4609                cx,
 4610            )
 4611        } else {
 4612            false
 4613        }
 4614    }
 4615
 4616    /// If any empty selections is touching the start of its innermost containing autoclose
 4617    /// region, expand it to select the brackets.
 4618    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4619        let selections = self.selections.all::<usize>(cx);
 4620        let buffer = self.buffer.read(cx).read(cx);
 4621        let new_selections = self
 4622            .selections_with_autoclose_regions(selections, &buffer)
 4623            .map(|(mut selection, region)| {
 4624                if !selection.is_empty() {
 4625                    return selection;
 4626                }
 4627
 4628                if let Some(region) = region {
 4629                    let mut range = region.range.to_offset(&buffer);
 4630                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4631                        range.start -= region.pair.start.len();
 4632                        if buffer.contains_str_at(range.start, &region.pair.start)
 4633                            && buffer.contains_str_at(range.end, &region.pair.end)
 4634                        {
 4635                            range.end += region.pair.end.len();
 4636                            selection.start = range.start;
 4637                            selection.end = range.end;
 4638
 4639                            return selection;
 4640                        }
 4641                    }
 4642                }
 4643
 4644                let always_treat_brackets_as_autoclosed = buffer
 4645                    .language_settings_at(selection.start, cx)
 4646                    .always_treat_brackets_as_autoclosed;
 4647
 4648                if !always_treat_brackets_as_autoclosed {
 4649                    return selection;
 4650                }
 4651
 4652                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4653                    for (pair, enabled) in scope.brackets() {
 4654                        if !enabled || !pair.close {
 4655                            continue;
 4656                        }
 4657
 4658                        if buffer.contains_str_at(selection.start, &pair.end) {
 4659                            let pair_start_len = pair.start.len();
 4660                            if buffer.contains_str_at(
 4661                                selection.start.saturating_sub(pair_start_len),
 4662                                &pair.start,
 4663                            ) {
 4664                                selection.start -= pair_start_len;
 4665                                selection.end += pair.end.len();
 4666
 4667                                return selection;
 4668                            }
 4669                        }
 4670                    }
 4671                }
 4672
 4673                selection
 4674            })
 4675            .collect();
 4676
 4677        drop(buffer);
 4678        self.change_selections(None, window, cx, |selections| {
 4679            selections.select(new_selections)
 4680        });
 4681    }
 4682
 4683    /// Iterate the given selections, and for each one, find the smallest surrounding
 4684    /// autoclose region. This uses the ordering of the selections and the autoclose
 4685    /// regions to avoid repeated comparisons.
 4686    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4687        &'a self,
 4688        selections: impl IntoIterator<Item = Selection<D>>,
 4689        buffer: &'a MultiBufferSnapshot,
 4690    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4691        let mut i = 0;
 4692        let mut regions = self.autoclose_regions.as_slice();
 4693        selections.into_iter().map(move |selection| {
 4694            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4695
 4696            let mut enclosing = None;
 4697            while let Some(pair_state) = regions.get(i) {
 4698                if pair_state.range.end.to_offset(buffer) < range.start {
 4699                    regions = &regions[i + 1..];
 4700                    i = 0;
 4701                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4702                    break;
 4703                } else {
 4704                    if pair_state.selection_id == selection.id {
 4705                        enclosing = Some(pair_state);
 4706                    }
 4707                    i += 1;
 4708                }
 4709            }
 4710
 4711            (selection, enclosing)
 4712        })
 4713    }
 4714
 4715    /// Remove any autoclose regions that no longer contain their selection.
 4716    fn invalidate_autoclose_regions(
 4717        &mut self,
 4718        mut selections: &[Selection<Anchor>],
 4719        buffer: &MultiBufferSnapshot,
 4720    ) {
 4721        self.autoclose_regions.retain(|state| {
 4722            let mut i = 0;
 4723            while let Some(selection) = selections.get(i) {
 4724                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4725                    selections = &selections[1..];
 4726                    continue;
 4727                }
 4728                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4729                    break;
 4730                }
 4731                if selection.id == state.selection_id {
 4732                    return true;
 4733                } else {
 4734                    i += 1;
 4735                }
 4736            }
 4737            false
 4738        });
 4739    }
 4740
 4741    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4742        let offset = position.to_offset(buffer);
 4743        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4744        if offset > word_range.start && kind == Some(CharKind::Word) {
 4745            Some(
 4746                buffer
 4747                    .text_for_range(word_range.start..offset)
 4748                    .collect::<String>(),
 4749            )
 4750        } else {
 4751            None
 4752        }
 4753    }
 4754
 4755    pub fn toggle_inline_values(
 4756        &mut self,
 4757        _: &ToggleInlineValues,
 4758        _: &mut Window,
 4759        cx: &mut Context<Self>,
 4760    ) {
 4761        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4762
 4763        self.refresh_inline_values(cx);
 4764    }
 4765
 4766    pub fn toggle_inlay_hints(
 4767        &mut self,
 4768        _: &ToggleInlayHints,
 4769        _: &mut Window,
 4770        cx: &mut Context<Self>,
 4771    ) {
 4772        self.refresh_inlay_hints(
 4773            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4774            cx,
 4775        );
 4776    }
 4777
 4778    pub fn inlay_hints_enabled(&self) -> bool {
 4779        self.inlay_hint_cache.enabled
 4780    }
 4781
 4782    pub fn inline_values_enabled(&self) -> bool {
 4783        self.inline_value_cache.enabled
 4784    }
 4785
 4786    #[cfg(any(test, feature = "test-support"))]
 4787    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4788        self.display_map
 4789            .read(cx)
 4790            .current_inlays()
 4791            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4792            .cloned()
 4793            .collect()
 4794    }
 4795
 4796    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4797        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4798            return;
 4799        }
 4800
 4801        let reason_description = reason.description();
 4802        let ignore_debounce = matches!(
 4803            reason,
 4804            InlayHintRefreshReason::SettingsChange(_)
 4805                | InlayHintRefreshReason::Toggle(_)
 4806                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4807                | InlayHintRefreshReason::ModifiersChanged(_)
 4808        );
 4809        let (invalidate_cache, required_languages) = match reason {
 4810            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4811                match self.inlay_hint_cache.modifiers_override(enabled) {
 4812                    Some(enabled) => {
 4813                        if enabled {
 4814                            (InvalidationStrategy::RefreshRequested, None)
 4815                        } else {
 4816                            self.splice_inlays(
 4817                                &self
 4818                                    .visible_inlay_hints(cx)
 4819                                    .iter()
 4820                                    .map(|inlay| inlay.id)
 4821                                    .collect::<Vec<InlayId>>(),
 4822                                Vec::new(),
 4823                                cx,
 4824                            );
 4825                            return;
 4826                        }
 4827                    }
 4828                    None => return,
 4829                }
 4830            }
 4831            InlayHintRefreshReason::Toggle(enabled) => {
 4832                if self.inlay_hint_cache.toggle(enabled) {
 4833                    if enabled {
 4834                        (InvalidationStrategy::RefreshRequested, None)
 4835                    } else {
 4836                        self.splice_inlays(
 4837                            &self
 4838                                .visible_inlay_hints(cx)
 4839                                .iter()
 4840                                .map(|inlay| inlay.id)
 4841                                .collect::<Vec<InlayId>>(),
 4842                            Vec::new(),
 4843                            cx,
 4844                        );
 4845                        return;
 4846                    }
 4847                } else {
 4848                    return;
 4849                }
 4850            }
 4851            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4852                match self.inlay_hint_cache.update_settings(
 4853                    &self.buffer,
 4854                    new_settings,
 4855                    self.visible_inlay_hints(cx),
 4856                    cx,
 4857                ) {
 4858                    ControlFlow::Break(Some(InlaySplice {
 4859                        to_remove,
 4860                        to_insert,
 4861                    })) => {
 4862                        self.splice_inlays(&to_remove, to_insert, cx);
 4863                        return;
 4864                    }
 4865                    ControlFlow::Break(None) => return,
 4866                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4867                }
 4868            }
 4869            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4870                if let Some(InlaySplice {
 4871                    to_remove,
 4872                    to_insert,
 4873                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4874                {
 4875                    self.splice_inlays(&to_remove, to_insert, cx);
 4876                }
 4877                self.display_map.update(cx, |display_map, _| {
 4878                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4879                });
 4880                return;
 4881            }
 4882            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4883            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4884                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4885            }
 4886            InlayHintRefreshReason::RefreshRequested => {
 4887                (InvalidationStrategy::RefreshRequested, None)
 4888            }
 4889        };
 4890
 4891        if let Some(InlaySplice {
 4892            to_remove,
 4893            to_insert,
 4894        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4895            reason_description,
 4896            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4897            invalidate_cache,
 4898            ignore_debounce,
 4899            cx,
 4900        ) {
 4901            self.splice_inlays(&to_remove, to_insert, cx);
 4902        }
 4903    }
 4904
 4905    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4906        self.display_map
 4907            .read(cx)
 4908            .current_inlays()
 4909            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4910            .cloned()
 4911            .collect()
 4912    }
 4913
 4914    pub fn excerpts_for_inlay_hints_query(
 4915        &self,
 4916        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4917        cx: &mut Context<Editor>,
 4918    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4919        let Some(project) = self.project.as_ref() else {
 4920            return HashMap::default();
 4921        };
 4922        let project = project.read(cx);
 4923        let multi_buffer = self.buffer().read(cx);
 4924        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4925        let multi_buffer_visible_start = self
 4926            .scroll_manager
 4927            .anchor()
 4928            .anchor
 4929            .to_point(&multi_buffer_snapshot);
 4930        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4931            multi_buffer_visible_start
 4932                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4933            Bias::Left,
 4934        );
 4935        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4936        multi_buffer_snapshot
 4937            .range_to_buffer_ranges(multi_buffer_visible_range)
 4938            .into_iter()
 4939            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4940            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4941                let buffer_file = project::File::from_dyn(buffer.file())?;
 4942                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4943                let worktree_entry = buffer_worktree
 4944                    .read(cx)
 4945                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4946                if worktree_entry.is_ignored {
 4947                    return None;
 4948                }
 4949
 4950                let language = buffer.language()?;
 4951                if let Some(restrict_to_languages) = restrict_to_languages {
 4952                    if !restrict_to_languages.contains(language) {
 4953                        return None;
 4954                    }
 4955                }
 4956                Some((
 4957                    excerpt_id,
 4958                    (
 4959                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4960                        buffer.version().clone(),
 4961                        excerpt_visible_range,
 4962                    ),
 4963                ))
 4964            })
 4965            .collect()
 4966    }
 4967
 4968    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4969        TextLayoutDetails {
 4970            text_system: window.text_system().clone(),
 4971            editor_style: self.style.clone().unwrap(),
 4972            rem_size: window.rem_size(),
 4973            scroll_anchor: self.scroll_manager.anchor(),
 4974            visible_rows: self.visible_line_count(),
 4975            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4976        }
 4977    }
 4978
 4979    pub fn splice_inlays(
 4980        &self,
 4981        to_remove: &[InlayId],
 4982        to_insert: Vec<Inlay>,
 4983        cx: &mut Context<Self>,
 4984    ) {
 4985        self.display_map.update(cx, |display_map, cx| {
 4986            display_map.splice_inlays(to_remove, to_insert, cx)
 4987        });
 4988        cx.notify();
 4989    }
 4990
 4991    fn trigger_on_type_formatting(
 4992        &self,
 4993        input: String,
 4994        window: &mut Window,
 4995        cx: &mut Context<Self>,
 4996    ) -> Option<Task<Result<()>>> {
 4997        if input.len() != 1 {
 4998            return None;
 4999        }
 5000
 5001        let project = self.project.as_ref()?;
 5002        let position = self.selections.newest_anchor().head();
 5003        let (buffer, buffer_position) = self
 5004            .buffer
 5005            .read(cx)
 5006            .text_anchor_for_position(position, cx)?;
 5007
 5008        let settings = language_settings::language_settings(
 5009            buffer
 5010                .read(cx)
 5011                .language_at(buffer_position)
 5012                .map(|l| l.name()),
 5013            buffer.read(cx).file(),
 5014            cx,
 5015        );
 5016        if !settings.use_on_type_format {
 5017            return None;
 5018        }
 5019
 5020        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5021        // hence we do LSP request & edit on host side only — add formats to host's history.
 5022        let push_to_lsp_host_history = true;
 5023        // If this is not the host, append its history with new edits.
 5024        let push_to_client_history = project.read(cx).is_via_collab();
 5025
 5026        let on_type_formatting = project.update(cx, |project, cx| {
 5027            project.on_type_format(
 5028                buffer.clone(),
 5029                buffer_position,
 5030                input,
 5031                push_to_lsp_host_history,
 5032                cx,
 5033            )
 5034        });
 5035        Some(cx.spawn_in(window, async move |editor, cx| {
 5036            if let Some(transaction) = on_type_formatting.await? {
 5037                if push_to_client_history {
 5038                    buffer
 5039                        .update(cx, |buffer, _| {
 5040                            buffer.push_transaction(transaction, Instant::now());
 5041                            buffer.finalize_last_transaction();
 5042                        })
 5043                        .ok();
 5044                }
 5045                editor.update(cx, |editor, cx| {
 5046                    editor.refresh_document_highlights(cx);
 5047                })?;
 5048            }
 5049            Ok(())
 5050        }))
 5051    }
 5052
 5053    pub fn show_word_completions(
 5054        &mut self,
 5055        _: &ShowWordCompletions,
 5056        window: &mut Window,
 5057        cx: &mut Context<Self>,
 5058    ) {
 5059        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5060    }
 5061
 5062    pub fn show_completions(
 5063        &mut self,
 5064        options: &ShowCompletions,
 5065        window: &mut Window,
 5066        cx: &mut Context<Self>,
 5067    ) {
 5068        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5069    }
 5070
 5071    fn open_or_update_completions_menu(
 5072        &mut self,
 5073        requested_source: Option<CompletionsMenuSource>,
 5074        trigger: Option<&str>,
 5075        window: &mut Window,
 5076        cx: &mut Context<Self>,
 5077    ) {
 5078        if self.pending_rename.is_some() {
 5079            return;
 5080        }
 5081
 5082        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5083
 5084        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5085        // inserted and selected. To handle that case, the start of the selection is used so that
 5086        // the menu starts with all choices.
 5087        let position = self
 5088            .selections
 5089            .newest_anchor()
 5090            .start
 5091            .bias_right(&multibuffer_snapshot);
 5092        if position.diff_base_anchor.is_some() {
 5093            return;
 5094        }
 5095        let (buffer, buffer_position) =
 5096            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5097                output
 5098            } else {
 5099                return;
 5100            };
 5101        let buffer_snapshot = buffer.read(cx).snapshot();
 5102
 5103        let query: Option<Arc<String>> =
 5104            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5105
 5106        drop(multibuffer_snapshot);
 5107
 5108        let provider = match requested_source {
 5109            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5110            Some(CompletionsMenuSource::Words) => None,
 5111            Some(CompletionsMenuSource::SnippetChoices) => {
 5112                log::error!("bug: SnippetChoices requested_source is not handled");
 5113                None
 5114            }
 5115        };
 5116
 5117        let sort_completions = provider
 5118            .as_ref()
 5119            .map_or(false, |provider| provider.sort_completions());
 5120
 5121        let filter_completions = provider
 5122            .as_ref()
 5123            .map_or(true, |provider| provider.filter_completions());
 5124
 5125        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5126        // current query is a suffix of the initial query.
 5127        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5128            if !menu.is_incomplete && filter_completions {
 5129                // If the new query is a suffix of the old query (typing more characters) and
 5130                // the previous result was complete, the existing completions can be filtered.
 5131                //
 5132                // Note that this is always true for snippet completions.
 5133                let query_matches = match (&menu.initial_query, &query) {
 5134                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5135                    (None, _) => true,
 5136                    _ => false,
 5137                };
 5138                if query_matches {
 5139                    let position_matches = if menu.initial_position == position {
 5140                        true
 5141                    } else {
 5142                        let snapshot = self.buffer.read(cx).read(cx);
 5143                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5144                    };
 5145                    if position_matches {
 5146                        menu.filter(query.clone(), provider.clone(), window, cx);
 5147                        return;
 5148                    }
 5149                }
 5150            }
 5151        };
 5152
 5153        let trigger_kind = match trigger {
 5154            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5155                CompletionTriggerKind::TRIGGER_CHARACTER
 5156            }
 5157            _ => CompletionTriggerKind::INVOKED,
 5158        };
 5159        let completion_context = CompletionContext {
 5160            trigger_character: trigger.and_then(|trigger| {
 5161                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5162                    Some(String::from(trigger))
 5163                } else {
 5164                    None
 5165                }
 5166            }),
 5167            trigger_kind,
 5168        };
 5169
 5170        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5171            buffer_snapshot.surrounding_word(buffer_position)
 5172        {
 5173            let word_to_exclude = buffer_snapshot
 5174                .text_for_range(word_range.clone())
 5175                .collect::<String>();
 5176            (
 5177                buffer_snapshot.anchor_before(word_range.start)
 5178                    ..buffer_snapshot.anchor_after(buffer_position),
 5179                Some(word_to_exclude),
 5180            )
 5181        } else {
 5182            (buffer_position..buffer_position, None)
 5183        };
 5184
 5185        let language = buffer_snapshot
 5186            .language_at(buffer_position)
 5187            .map(|language| language.name());
 5188
 5189        let completion_settings =
 5190            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5191
 5192        let show_completion_documentation = buffer_snapshot
 5193            .settings_at(buffer_position, cx)
 5194            .show_completion_documentation;
 5195
 5196        // The document can be large, so stay in reasonable bounds when searching for words,
 5197        // otherwise completion pop-up might be slow to appear.
 5198        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5199        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5200        let min_word_search = buffer_snapshot.clip_point(
 5201            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5202            Bias::Left,
 5203        );
 5204        let max_word_search = buffer_snapshot.clip_point(
 5205            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5206            Bias::Right,
 5207        );
 5208        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5209            ..buffer_snapshot.point_to_offset(max_word_search);
 5210
 5211        let skip_digits = query
 5212            .as_ref()
 5213            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5214
 5215        let (mut words, provider_responses) = match &provider {
 5216            Some(provider) => {
 5217                let provider_responses = provider.completions(
 5218                    position.excerpt_id,
 5219                    &buffer,
 5220                    buffer_position,
 5221                    completion_context,
 5222                    window,
 5223                    cx,
 5224                );
 5225
 5226                let words = match completion_settings.words {
 5227                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5228                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5229                        .background_spawn(async move {
 5230                            buffer_snapshot.words_in_range(WordsQuery {
 5231                                fuzzy_contents: None,
 5232                                range: word_search_range,
 5233                                skip_digits,
 5234                            })
 5235                        }),
 5236                };
 5237
 5238                (words, provider_responses)
 5239            }
 5240            None => (
 5241                cx.background_spawn(async move {
 5242                    buffer_snapshot.words_in_range(WordsQuery {
 5243                        fuzzy_contents: None,
 5244                        range: word_search_range,
 5245                        skip_digits,
 5246                    })
 5247                }),
 5248                Task::ready(Ok(Vec::new())),
 5249            ),
 5250        };
 5251
 5252        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5253
 5254        let id = post_inc(&mut self.next_completion_id);
 5255        let task = cx.spawn_in(window, async move |editor, cx| {
 5256            let Ok(()) = editor.update(cx, |this, _| {
 5257                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5258            }) else {
 5259                return;
 5260            };
 5261
 5262            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5263            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5264            let mut completions = Vec::new();
 5265            let mut is_incomplete = false;
 5266            if let Some(provider_responses) = provider_responses.await.log_err() {
 5267                if !provider_responses.is_empty() {
 5268                    for response in provider_responses {
 5269                        completions.extend(response.completions);
 5270                        is_incomplete = is_incomplete || response.is_incomplete;
 5271                    }
 5272                    if completion_settings.words == WordsCompletionMode::Fallback {
 5273                        words = Task::ready(BTreeMap::default());
 5274                    }
 5275                }
 5276            }
 5277
 5278            let mut words = words.await;
 5279            if let Some(word_to_exclude) = &word_to_exclude {
 5280                words.remove(word_to_exclude);
 5281            }
 5282            for lsp_completion in &completions {
 5283                words.remove(&lsp_completion.new_text);
 5284            }
 5285            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5286                replace_range: word_replace_range.clone(),
 5287                new_text: word.clone(),
 5288                label: CodeLabel::plain(word, None),
 5289                icon_path: None,
 5290                documentation: None,
 5291                source: CompletionSource::BufferWord {
 5292                    word_range,
 5293                    resolved: false,
 5294                },
 5295                insert_text_mode: Some(InsertTextMode::AS_IS),
 5296                confirm: None,
 5297            }));
 5298
 5299            let menu = if completions.is_empty() {
 5300                None
 5301            } else {
 5302                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5303                    let languages = editor
 5304                        .workspace
 5305                        .as_ref()
 5306                        .and_then(|(workspace, _)| workspace.upgrade())
 5307                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5308                    let menu = CompletionsMenu::new(
 5309                        id,
 5310                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5311                        sort_completions,
 5312                        show_completion_documentation,
 5313                        position,
 5314                        query.clone(),
 5315                        is_incomplete,
 5316                        buffer.clone(),
 5317                        completions.into(),
 5318                        snippet_sort_order,
 5319                        languages,
 5320                        language,
 5321                        cx,
 5322                    );
 5323
 5324                    let query = if filter_completions { query } else { None };
 5325                    let matches_task = if let Some(query) = query {
 5326                        menu.do_async_filtering(query, cx)
 5327                    } else {
 5328                        Task::ready(menu.unfiltered_matches())
 5329                    };
 5330                    (menu, matches_task)
 5331                }) else {
 5332                    return;
 5333                };
 5334
 5335                let matches = matches_task.await;
 5336
 5337                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5338                    // Newer menu already set, so exit.
 5339                    match editor.context_menu.borrow().as_ref() {
 5340                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5341                            if prev_menu.id > id {
 5342                                return;
 5343                            }
 5344                        }
 5345                        _ => {}
 5346                    };
 5347
 5348                    // Only valid to take prev_menu because it the new menu is immediately set
 5349                    // below, or the menu is hidden.
 5350                    match editor.context_menu.borrow_mut().take() {
 5351                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5352                            let position_matches =
 5353                                if prev_menu.initial_position == menu.initial_position {
 5354                                    true
 5355                                } else {
 5356                                    let snapshot = editor.buffer.read(cx).read(cx);
 5357                                    prev_menu.initial_position.to_offset(&snapshot)
 5358                                        == menu.initial_position.to_offset(&snapshot)
 5359                                };
 5360                            if position_matches {
 5361                                // Preserve markdown cache before `set_filter_results` because it will
 5362                                // try to populate the documentation cache.
 5363                                menu.preserve_markdown_cache(prev_menu);
 5364                            }
 5365                        }
 5366                        _ => {}
 5367                    };
 5368
 5369                    menu.set_filter_results(matches, provider, window, cx);
 5370                }) else {
 5371                    return;
 5372                };
 5373
 5374                menu.visible().then_some(menu)
 5375            };
 5376
 5377            editor
 5378                .update_in(cx, |editor, window, cx| {
 5379                    if editor.focus_handle.is_focused(window) {
 5380                        if let Some(menu) = menu {
 5381                            *editor.context_menu.borrow_mut() =
 5382                                Some(CodeContextMenu::Completions(menu));
 5383
 5384                            crate::hover_popover::hide_hover(editor, cx);
 5385                            if editor.show_edit_predictions_in_menu() {
 5386                                editor.update_visible_inline_completion(window, cx);
 5387                            } else {
 5388                                editor.discard_inline_completion(false, cx);
 5389                            }
 5390
 5391                            cx.notify();
 5392                            return;
 5393                        }
 5394                    }
 5395
 5396                    if editor.completion_tasks.len() <= 1 {
 5397                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5398                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5399                        // If it was already hidden and we don't show inline completions in the menu, we should
 5400                        // also show the inline-completion when available.
 5401                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5402                            editor.update_visible_inline_completion(window, cx);
 5403                        }
 5404                    }
 5405                })
 5406                .ok();
 5407        });
 5408
 5409        self.completion_tasks.push((id, task));
 5410    }
 5411
 5412    #[cfg(feature = "test-support")]
 5413    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5414        let menu = self.context_menu.borrow();
 5415        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5416            let completions = menu.completions.borrow();
 5417            Some(completions.to_vec())
 5418        } else {
 5419            None
 5420        }
 5421    }
 5422
 5423    pub fn with_completions_menu_matching_id<R>(
 5424        &self,
 5425        id: CompletionId,
 5426        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5427    ) -> R {
 5428        let mut context_menu = self.context_menu.borrow_mut();
 5429        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5430            return f(None);
 5431        };
 5432        if completions_menu.id != id {
 5433            return f(None);
 5434        }
 5435        f(Some(completions_menu))
 5436    }
 5437
 5438    pub fn confirm_completion(
 5439        &mut self,
 5440        action: &ConfirmCompletion,
 5441        window: &mut Window,
 5442        cx: &mut Context<Self>,
 5443    ) -> Option<Task<Result<()>>> {
 5444        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5445        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5446    }
 5447
 5448    pub fn confirm_completion_insert(
 5449        &mut self,
 5450        _: &ConfirmCompletionInsert,
 5451        window: &mut Window,
 5452        cx: &mut Context<Self>,
 5453    ) -> Option<Task<Result<()>>> {
 5454        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5455        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5456    }
 5457
 5458    pub fn confirm_completion_replace(
 5459        &mut self,
 5460        _: &ConfirmCompletionReplace,
 5461        window: &mut Window,
 5462        cx: &mut Context<Self>,
 5463    ) -> Option<Task<Result<()>>> {
 5464        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5465        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5466    }
 5467
 5468    pub fn compose_completion(
 5469        &mut self,
 5470        action: &ComposeCompletion,
 5471        window: &mut Window,
 5472        cx: &mut Context<Self>,
 5473    ) -> Option<Task<Result<()>>> {
 5474        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5475        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5476    }
 5477
 5478    fn do_completion(
 5479        &mut self,
 5480        item_ix: Option<usize>,
 5481        intent: CompletionIntent,
 5482        window: &mut Window,
 5483        cx: &mut Context<Editor>,
 5484    ) -> Option<Task<Result<()>>> {
 5485        use language::ToOffset as _;
 5486
 5487        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5488        else {
 5489            return None;
 5490        };
 5491
 5492        let candidate_id = {
 5493            let entries = completions_menu.entries.borrow();
 5494            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5495            if self.show_edit_predictions_in_menu() {
 5496                self.discard_inline_completion(true, cx);
 5497            }
 5498            mat.candidate_id
 5499        };
 5500
 5501        let completion = completions_menu
 5502            .completions
 5503            .borrow()
 5504            .get(candidate_id)?
 5505            .clone();
 5506        cx.stop_propagation();
 5507
 5508        let buffer_handle = completions_menu.buffer.clone();
 5509
 5510        let CompletionEdit {
 5511            new_text,
 5512            snippet,
 5513            replace_range,
 5514        } = process_completion_for_edit(
 5515            &completion,
 5516            intent,
 5517            &buffer_handle,
 5518            &completions_menu.initial_position.text_anchor,
 5519            cx,
 5520        );
 5521
 5522        let buffer = buffer_handle.read(cx);
 5523        let snapshot = self.buffer.read(cx).snapshot(cx);
 5524        let newest_anchor = self.selections.newest_anchor();
 5525        let replace_range_multibuffer = {
 5526            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5527            let multibuffer_anchor = snapshot
 5528                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5529                .unwrap()
 5530                ..snapshot
 5531                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5532                    .unwrap();
 5533            multibuffer_anchor.start.to_offset(&snapshot)
 5534                ..multibuffer_anchor.end.to_offset(&snapshot)
 5535        };
 5536        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5537            return None;
 5538        }
 5539
 5540        let old_text = buffer
 5541            .text_for_range(replace_range.clone())
 5542            .collect::<String>();
 5543        let lookbehind = newest_anchor
 5544            .start
 5545            .text_anchor
 5546            .to_offset(buffer)
 5547            .saturating_sub(replace_range.start);
 5548        let lookahead = replace_range
 5549            .end
 5550            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5551        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5552        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5553
 5554        let selections = self.selections.all::<usize>(cx);
 5555        let mut ranges = Vec::new();
 5556        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5557
 5558        for selection in &selections {
 5559            let range = if selection.id == newest_anchor.id {
 5560                replace_range_multibuffer.clone()
 5561            } else {
 5562                let mut range = selection.range();
 5563
 5564                // if prefix is present, don't duplicate it
 5565                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5566                    range.start = range.start.saturating_sub(lookbehind);
 5567
 5568                    // if suffix is also present, mimic the newest cursor and replace it
 5569                    if selection.id != newest_anchor.id
 5570                        && snapshot.contains_str_at(range.end, suffix)
 5571                    {
 5572                        range.end += lookahead;
 5573                    }
 5574                }
 5575                range
 5576            };
 5577
 5578            ranges.push(range.clone());
 5579
 5580            if !self.linked_edit_ranges.is_empty() {
 5581                let start_anchor = snapshot.anchor_before(range.start);
 5582                let end_anchor = snapshot.anchor_after(range.end);
 5583                if let Some(ranges) = self
 5584                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5585                {
 5586                    for (buffer, edits) in ranges {
 5587                        linked_edits
 5588                            .entry(buffer.clone())
 5589                            .or_default()
 5590                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5591                    }
 5592                }
 5593            }
 5594        }
 5595
 5596        let common_prefix_len = old_text
 5597            .chars()
 5598            .zip(new_text.chars())
 5599            .take_while(|(a, b)| a == b)
 5600            .map(|(a, _)| a.len_utf8())
 5601            .sum::<usize>();
 5602
 5603        cx.emit(EditorEvent::InputHandled {
 5604            utf16_range_to_replace: None,
 5605            text: new_text[common_prefix_len..].into(),
 5606        });
 5607
 5608        self.transact(window, cx, |this, window, cx| {
 5609            if let Some(mut snippet) = snippet {
 5610                snippet.text = new_text.to_string();
 5611                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5612            } else {
 5613                this.buffer.update(cx, |buffer, cx| {
 5614                    let auto_indent = match completion.insert_text_mode {
 5615                        Some(InsertTextMode::AS_IS) => None,
 5616                        _ => this.autoindent_mode.clone(),
 5617                    };
 5618                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5619                    buffer.edit(edits, auto_indent, cx);
 5620                });
 5621            }
 5622            for (buffer, edits) in linked_edits {
 5623                buffer.update(cx, |buffer, cx| {
 5624                    let snapshot = buffer.snapshot();
 5625                    let edits = edits
 5626                        .into_iter()
 5627                        .map(|(range, text)| {
 5628                            use text::ToPoint as TP;
 5629                            let end_point = TP::to_point(&range.end, &snapshot);
 5630                            let start_point = TP::to_point(&range.start, &snapshot);
 5631                            (start_point..end_point, text)
 5632                        })
 5633                        .sorted_by_key(|(range, _)| range.start);
 5634                    buffer.edit(edits, None, cx);
 5635                })
 5636            }
 5637
 5638            this.refresh_inline_completion(true, false, window, cx);
 5639        });
 5640
 5641        let show_new_completions_on_confirm = completion
 5642            .confirm
 5643            .as_ref()
 5644            .map_or(false, |confirm| confirm(intent, window, cx));
 5645        if show_new_completions_on_confirm {
 5646            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5647        }
 5648
 5649        let provider = self.completion_provider.as_ref()?;
 5650        drop(completion);
 5651        let apply_edits = provider.apply_additional_edits_for_completion(
 5652            buffer_handle,
 5653            completions_menu.completions.clone(),
 5654            candidate_id,
 5655            true,
 5656            cx,
 5657        );
 5658
 5659        let editor_settings = EditorSettings::get_global(cx);
 5660        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5661            // After the code completion is finished, users often want to know what signatures are needed.
 5662            // so we should automatically call signature_help
 5663            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5664        }
 5665
 5666        Some(cx.foreground_executor().spawn(async move {
 5667            apply_edits.await?;
 5668            Ok(())
 5669        }))
 5670    }
 5671
 5672    pub fn toggle_code_actions(
 5673        &mut self,
 5674        action: &ToggleCodeActions,
 5675        window: &mut Window,
 5676        cx: &mut Context<Self>,
 5677    ) {
 5678        let quick_launch = action.quick_launch;
 5679        let mut context_menu = self.context_menu.borrow_mut();
 5680        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5681            if code_actions.deployed_from == action.deployed_from {
 5682                // Toggle if we're selecting the same one
 5683                *context_menu = None;
 5684                cx.notify();
 5685                return;
 5686            } else {
 5687                // Otherwise, clear it and start a new one
 5688                *context_menu = None;
 5689                cx.notify();
 5690            }
 5691        }
 5692        drop(context_menu);
 5693        let snapshot = self.snapshot(window, cx);
 5694        let deployed_from = action.deployed_from.clone();
 5695        let mut task = self.code_actions_task.take();
 5696        let action = action.clone();
 5697        cx.spawn_in(window, async move |editor, cx| {
 5698            while let Some(prev_task) = task {
 5699                prev_task.await.log_err();
 5700                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5701            }
 5702
 5703            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5704                if editor.focus_handle.is_focused(window) {
 5705                    let multibuffer_point = match &action.deployed_from {
 5706                        Some(CodeActionSource::Indicator(row)) => {
 5707                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5708                        }
 5709                        _ => editor.selections.newest::<Point>(cx).head(),
 5710                    };
 5711                    let (buffer, buffer_row) = snapshot
 5712                        .buffer_snapshot
 5713                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5714                        .and_then(|(buffer_snapshot, range)| {
 5715                            editor
 5716                                .buffer
 5717                                .read(cx)
 5718                                .buffer(buffer_snapshot.remote_id())
 5719                                .map(|buffer| (buffer, range.start.row))
 5720                        })?;
 5721                    let (_, code_actions) = editor
 5722                        .available_code_actions
 5723                        .clone()
 5724                        .and_then(|(location, code_actions)| {
 5725                            let snapshot = location.buffer.read(cx).snapshot();
 5726                            let point_range = location.range.to_point(&snapshot);
 5727                            let point_range = point_range.start.row..=point_range.end.row;
 5728                            if point_range.contains(&buffer_row) {
 5729                                Some((location, code_actions))
 5730                            } else {
 5731                                None
 5732                            }
 5733                        })
 5734                        .unzip();
 5735                    let buffer_id = buffer.read(cx).remote_id();
 5736                    let tasks = editor
 5737                        .tasks
 5738                        .get(&(buffer_id, buffer_row))
 5739                        .map(|t| Arc::new(t.to_owned()));
 5740                    if tasks.is_none() && code_actions.is_none() {
 5741                        return None;
 5742                    }
 5743
 5744                    editor.completion_tasks.clear();
 5745                    editor.discard_inline_completion(false, cx);
 5746                    let task_context =
 5747                        tasks
 5748                            .as_ref()
 5749                            .zip(editor.project.clone())
 5750                            .map(|(tasks, project)| {
 5751                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5752                            });
 5753
 5754                    Some(cx.spawn_in(window, async move |editor, cx| {
 5755                        let task_context = match task_context {
 5756                            Some(task_context) => task_context.await,
 5757                            None => None,
 5758                        };
 5759                        let resolved_tasks =
 5760                            tasks
 5761                                .zip(task_context.clone())
 5762                                .map(|(tasks, task_context)| ResolvedTasks {
 5763                                    templates: tasks.resolve(&task_context).collect(),
 5764                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5765                                        multibuffer_point.row,
 5766                                        tasks.column,
 5767                                    )),
 5768                                });
 5769                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5770                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5771                                maybe!({
 5772                                    let project = editor.project.as_ref()?;
 5773                                    let dap_store = project.read(cx).dap_store();
 5774                                    let mut scenarios = vec![];
 5775                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5776                                    let buffer = buffer.read(cx);
 5777                                    let language = buffer.language()?;
 5778                                    let file = buffer.file();
 5779                                    let debug_adapter =
 5780                                        language_settings(language.name().into(), file, cx)
 5781                                            .debuggers
 5782                                            .first()
 5783                                            .map(SharedString::from)
 5784                                            .or_else(|| {
 5785                                                language
 5786                                                    .config()
 5787                                                    .debuggers
 5788                                                    .first()
 5789                                                    .map(SharedString::from)
 5790                                            })?;
 5791
 5792                                    dap_store.update(cx, |dap_store, cx| {
 5793                                        for (_, task) in &resolved_tasks.templates {
 5794                                            if let Some(scenario) = dap_store
 5795                                                .debug_scenario_for_build_task(
 5796                                                    task.original_task().clone(),
 5797                                                    debug_adapter.clone().into(),
 5798                                                    task.display_label().to_owned().into(),
 5799                                                    cx,
 5800                                                )
 5801                                            {
 5802                                                scenarios.push(scenario);
 5803                                            }
 5804                                        }
 5805                                    });
 5806                                    Some(scenarios)
 5807                                })
 5808                                .unwrap_or_default()
 5809                            } else {
 5810                                vec![]
 5811                            }
 5812                        })?;
 5813                        let spawn_straight_away = quick_launch
 5814                            && resolved_tasks
 5815                                .as_ref()
 5816                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5817                            && code_actions
 5818                                .as_ref()
 5819                                .map_or(true, |actions| actions.is_empty())
 5820                            && debug_scenarios.is_empty();
 5821                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5822                            crate::hover_popover::hide_hover(editor, cx);
 5823                            *editor.context_menu.borrow_mut() =
 5824                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5825                                    buffer,
 5826                                    actions: CodeActionContents::new(
 5827                                        resolved_tasks,
 5828                                        code_actions,
 5829                                        debug_scenarios,
 5830                                        task_context.unwrap_or_default(),
 5831                                    ),
 5832                                    selected_item: Default::default(),
 5833                                    scroll_handle: UniformListScrollHandle::default(),
 5834                                    deployed_from,
 5835                                }));
 5836                            if spawn_straight_away {
 5837                                if let Some(task) = editor.confirm_code_action(
 5838                                    &ConfirmCodeAction { item_ix: Some(0) },
 5839                                    window,
 5840                                    cx,
 5841                                ) {
 5842                                    cx.notify();
 5843                                    return task;
 5844                                }
 5845                            }
 5846                            cx.notify();
 5847                            Task::ready(Ok(()))
 5848                        }) {
 5849                            task.await
 5850                        } else {
 5851                            Ok(())
 5852                        }
 5853                    }))
 5854                } else {
 5855                    Some(Task::ready(Ok(())))
 5856                }
 5857            })?;
 5858            if let Some(task) = spawned_test_task {
 5859                task.await?;
 5860            }
 5861
 5862            anyhow::Ok(())
 5863        })
 5864        .detach_and_log_err(cx);
 5865    }
 5866
 5867    pub fn confirm_code_action(
 5868        &mut self,
 5869        action: &ConfirmCodeAction,
 5870        window: &mut Window,
 5871        cx: &mut Context<Self>,
 5872    ) -> Option<Task<Result<()>>> {
 5873        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5874
 5875        let actions_menu =
 5876            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5877                menu
 5878            } else {
 5879                return None;
 5880            };
 5881
 5882        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5883        let action = actions_menu.actions.get(action_ix)?;
 5884        let title = action.label();
 5885        let buffer = actions_menu.buffer;
 5886        let workspace = self.workspace()?;
 5887
 5888        match action {
 5889            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5890                workspace.update(cx, |workspace, cx| {
 5891                    workspace.schedule_resolved_task(
 5892                        task_source_kind,
 5893                        resolved_task,
 5894                        false,
 5895                        window,
 5896                        cx,
 5897                    );
 5898
 5899                    Some(Task::ready(Ok(())))
 5900                })
 5901            }
 5902            CodeActionsItem::CodeAction {
 5903                excerpt_id,
 5904                action,
 5905                provider,
 5906            } => {
 5907                let apply_code_action =
 5908                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5909                let workspace = workspace.downgrade();
 5910                Some(cx.spawn_in(window, async move |editor, cx| {
 5911                    let project_transaction = apply_code_action.await?;
 5912                    Self::open_project_transaction(
 5913                        &editor,
 5914                        workspace,
 5915                        project_transaction,
 5916                        title,
 5917                        cx,
 5918                    )
 5919                    .await
 5920                }))
 5921            }
 5922            CodeActionsItem::DebugScenario(scenario) => {
 5923                let context = actions_menu.actions.context.clone();
 5924
 5925                workspace.update(cx, |workspace, cx| {
 5926                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5927                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5928                });
 5929                Some(Task::ready(Ok(())))
 5930            }
 5931        }
 5932    }
 5933
 5934    pub async fn open_project_transaction(
 5935        this: &WeakEntity<Editor>,
 5936        workspace: WeakEntity<Workspace>,
 5937        transaction: ProjectTransaction,
 5938        title: String,
 5939        cx: &mut AsyncWindowContext,
 5940    ) -> Result<()> {
 5941        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5942        cx.update(|_, cx| {
 5943            entries.sort_unstable_by_key(|(buffer, _)| {
 5944                buffer.read(cx).file().map(|f| f.path().clone())
 5945            });
 5946        })?;
 5947
 5948        // If the project transaction's edits are all contained within this editor, then
 5949        // avoid opening a new editor to display them.
 5950
 5951        if let Some((buffer, transaction)) = entries.first() {
 5952            if entries.len() == 1 {
 5953                let excerpt = this.update(cx, |editor, cx| {
 5954                    editor
 5955                        .buffer()
 5956                        .read(cx)
 5957                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5958                })?;
 5959                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5960                    if excerpted_buffer == *buffer {
 5961                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5962                            let excerpt_range = excerpt_range.to_offset(buffer);
 5963                            buffer
 5964                                .edited_ranges_for_transaction::<usize>(transaction)
 5965                                .all(|range| {
 5966                                    excerpt_range.start <= range.start
 5967                                        && excerpt_range.end >= range.end
 5968                                })
 5969                        })?;
 5970
 5971                        if all_edits_within_excerpt {
 5972                            return Ok(());
 5973                        }
 5974                    }
 5975                }
 5976            }
 5977        } else {
 5978            return Ok(());
 5979        }
 5980
 5981        let mut ranges_to_highlight = Vec::new();
 5982        let excerpt_buffer = cx.new(|cx| {
 5983            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5984            for (buffer_handle, transaction) in &entries {
 5985                let edited_ranges = buffer_handle
 5986                    .read(cx)
 5987                    .edited_ranges_for_transaction::<Point>(transaction)
 5988                    .collect::<Vec<_>>();
 5989                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5990                    PathKey::for_buffer(buffer_handle, cx),
 5991                    buffer_handle.clone(),
 5992                    edited_ranges,
 5993                    DEFAULT_MULTIBUFFER_CONTEXT,
 5994                    cx,
 5995                );
 5996
 5997                ranges_to_highlight.extend(ranges);
 5998            }
 5999            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6000            multibuffer
 6001        })?;
 6002
 6003        workspace.update_in(cx, |workspace, window, cx| {
 6004            let project = workspace.project().clone();
 6005            let editor =
 6006                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6007            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6008            editor.update(cx, |editor, cx| {
 6009                editor.highlight_background::<Self>(
 6010                    &ranges_to_highlight,
 6011                    |theme| theme.editor_highlighted_line_background,
 6012                    cx,
 6013                );
 6014            });
 6015        })?;
 6016
 6017        Ok(())
 6018    }
 6019
 6020    pub fn clear_code_action_providers(&mut self) {
 6021        self.code_action_providers.clear();
 6022        self.available_code_actions.take();
 6023    }
 6024
 6025    pub fn add_code_action_provider(
 6026        &mut self,
 6027        provider: Rc<dyn CodeActionProvider>,
 6028        window: &mut Window,
 6029        cx: &mut Context<Self>,
 6030    ) {
 6031        if self
 6032            .code_action_providers
 6033            .iter()
 6034            .any(|existing_provider| existing_provider.id() == provider.id())
 6035        {
 6036            return;
 6037        }
 6038
 6039        self.code_action_providers.push(provider);
 6040        self.refresh_code_actions(window, cx);
 6041    }
 6042
 6043    pub fn remove_code_action_provider(
 6044        &mut self,
 6045        id: Arc<str>,
 6046        window: &mut Window,
 6047        cx: &mut Context<Self>,
 6048    ) {
 6049        self.code_action_providers
 6050            .retain(|provider| provider.id() != id);
 6051        self.refresh_code_actions(window, cx);
 6052    }
 6053
 6054    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6055        !self.code_action_providers.is_empty()
 6056            && EditorSettings::get_global(cx).toolbar.code_actions
 6057    }
 6058
 6059    pub fn has_available_code_actions(&self) -> bool {
 6060        self.available_code_actions
 6061            .as_ref()
 6062            .is_some_and(|(_, actions)| !actions.is_empty())
 6063    }
 6064
 6065    fn render_inline_code_actions(
 6066        &self,
 6067        icon_size: ui::IconSize,
 6068        display_row: DisplayRow,
 6069        is_active: bool,
 6070        cx: &mut Context<Self>,
 6071    ) -> AnyElement {
 6072        let show_tooltip = !self.context_menu_visible();
 6073        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6074            .icon_size(icon_size)
 6075            .shape(ui::IconButtonShape::Square)
 6076            .style(ButtonStyle::Transparent)
 6077            .icon_color(ui::Color::Hidden)
 6078            .toggle_state(is_active)
 6079            .when(show_tooltip, |this| {
 6080                this.tooltip({
 6081                    let focus_handle = self.focus_handle.clone();
 6082                    move |window, cx| {
 6083                        Tooltip::for_action_in(
 6084                            "Toggle Code Actions",
 6085                            &ToggleCodeActions {
 6086                                deployed_from: None,
 6087                                quick_launch: false,
 6088                            },
 6089                            &focus_handle,
 6090                            window,
 6091                            cx,
 6092                        )
 6093                    }
 6094                })
 6095            })
 6096            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6097                window.focus(&editor.focus_handle(cx));
 6098                editor.toggle_code_actions(
 6099                    &crate::actions::ToggleCodeActions {
 6100                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6101                            display_row,
 6102                        )),
 6103                        quick_launch: false,
 6104                    },
 6105                    window,
 6106                    cx,
 6107                );
 6108            }))
 6109            .into_any_element()
 6110    }
 6111
 6112    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6113        &self.context_menu
 6114    }
 6115
 6116    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6117        let newest_selection = self.selections.newest_anchor().clone();
 6118        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6119        let buffer = self.buffer.read(cx);
 6120        if newest_selection.head().diff_base_anchor.is_some() {
 6121            return None;
 6122        }
 6123        let (start_buffer, start) =
 6124            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6125        let (end_buffer, end) =
 6126            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6127        if start_buffer != end_buffer {
 6128            return None;
 6129        }
 6130
 6131        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6132            cx.background_executor()
 6133                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6134                .await;
 6135
 6136            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6137                let providers = this.code_action_providers.clone();
 6138                let tasks = this
 6139                    .code_action_providers
 6140                    .iter()
 6141                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6142                    .collect::<Vec<_>>();
 6143                (providers, tasks)
 6144            })?;
 6145
 6146            let mut actions = Vec::new();
 6147            for (provider, provider_actions) in
 6148                providers.into_iter().zip(future::join_all(tasks).await)
 6149            {
 6150                if let Some(provider_actions) = provider_actions.log_err() {
 6151                    actions.extend(provider_actions.into_iter().map(|action| {
 6152                        AvailableCodeAction {
 6153                            excerpt_id: newest_selection.start.excerpt_id,
 6154                            action,
 6155                            provider: provider.clone(),
 6156                        }
 6157                    }));
 6158                }
 6159            }
 6160
 6161            this.update(cx, |this, cx| {
 6162                this.available_code_actions = if actions.is_empty() {
 6163                    None
 6164                } else {
 6165                    Some((
 6166                        Location {
 6167                            buffer: start_buffer,
 6168                            range: start..end,
 6169                        },
 6170                        actions.into(),
 6171                    ))
 6172                };
 6173                cx.notify();
 6174            })
 6175        }));
 6176        None
 6177    }
 6178
 6179    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6180        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6181            self.show_git_blame_inline = false;
 6182
 6183            self.show_git_blame_inline_delay_task =
 6184                Some(cx.spawn_in(window, async move |this, cx| {
 6185                    cx.background_executor().timer(delay).await;
 6186
 6187                    this.update(cx, |this, cx| {
 6188                        this.show_git_blame_inline = true;
 6189                        cx.notify();
 6190                    })
 6191                    .log_err();
 6192                }));
 6193        }
 6194    }
 6195
 6196    fn show_blame_popover(
 6197        &mut self,
 6198        blame_entry: &BlameEntry,
 6199        position: gpui::Point<Pixels>,
 6200        cx: &mut Context<Self>,
 6201    ) {
 6202        if let Some(state) = &mut self.inline_blame_popover {
 6203            state.hide_task.take();
 6204            cx.notify();
 6205        } else {
 6206            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6207            let show_task = cx.spawn(async move |editor, cx| {
 6208                cx.background_executor()
 6209                    .timer(std::time::Duration::from_millis(delay))
 6210                    .await;
 6211                editor
 6212                    .update(cx, |editor, cx| {
 6213                        if let Some(state) = &mut editor.inline_blame_popover {
 6214                            state.show_task = None;
 6215                            cx.notify();
 6216                        }
 6217                    })
 6218                    .ok();
 6219            });
 6220            let Some(blame) = self.blame.as_ref() else {
 6221                return;
 6222            };
 6223            let blame = blame.read(cx);
 6224            let details = blame.details_for_entry(&blame_entry);
 6225            let markdown = cx.new(|cx| {
 6226                Markdown::new(
 6227                    details
 6228                        .as_ref()
 6229                        .map(|message| message.message.clone())
 6230                        .unwrap_or_default(),
 6231                    None,
 6232                    None,
 6233                    cx,
 6234                )
 6235            });
 6236            self.inline_blame_popover = Some(InlineBlamePopover {
 6237                position,
 6238                show_task: Some(show_task),
 6239                hide_task: None,
 6240                popover_bounds: None,
 6241                popover_state: InlineBlamePopoverState {
 6242                    scroll_handle: ScrollHandle::new(),
 6243                    commit_message: details,
 6244                    markdown,
 6245                },
 6246            });
 6247        }
 6248    }
 6249
 6250    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6251        if let Some(state) = &mut self.inline_blame_popover {
 6252            if state.show_task.is_some() {
 6253                self.inline_blame_popover.take();
 6254                cx.notify();
 6255            } else {
 6256                let hide_task = cx.spawn(async move |editor, cx| {
 6257                    cx.background_executor()
 6258                        .timer(std::time::Duration::from_millis(100))
 6259                        .await;
 6260                    editor
 6261                        .update(cx, |editor, cx| {
 6262                            editor.inline_blame_popover.take();
 6263                            cx.notify();
 6264                        })
 6265                        .ok();
 6266                });
 6267                state.hide_task = Some(hide_task);
 6268            }
 6269        }
 6270    }
 6271
 6272    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6273        if self.pending_rename.is_some() {
 6274            return None;
 6275        }
 6276
 6277        let provider = self.semantics_provider.clone()?;
 6278        let buffer = self.buffer.read(cx);
 6279        let newest_selection = self.selections.newest_anchor().clone();
 6280        let cursor_position = newest_selection.head();
 6281        let (cursor_buffer, cursor_buffer_position) =
 6282            buffer.text_anchor_for_position(cursor_position, cx)?;
 6283        let (tail_buffer, tail_buffer_position) =
 6284            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6285        if cursor_buffer != tail_buffer {
 6286            return None;
 6287        }
 6288
 6289        let snapshot = cursor_buffer.read(cx).snapshot();
 6290        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6291        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6292        if start_word_range != end_word_range {
 6293            self.document_highlights_task.take();
 6294            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6295            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6296            return None;
 6297        }
 6298
 6299        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6300        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6301            cx.background_executor()
 6302                .timer(Duration::from_millis(debounce))
 6303                .await;
 6304
 6305            let highlights = if let Some(highlights) = cx
 6306                .update(|cx| {
 6307                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6308                })
 6309                .ok()
 6310                .flatten()
 6311            {
 6312                highlights.await.log_err()
 6313            } else {
 6314                None
 6315            };
 6316
 6317            if let Some(highlights) = highlights {
 6318                this.update(cx, |this, cx| {
 6319                    if this.pending_rename.is_some() {
 6320                        return;
 6321                    }
 6322
 6323                    let buffer_id = cursor_position.buffer_id;
 6324                    let buffer = this.buffer.read(cx);
 6325                    if !buffer
 6326                        .text_anchor_for_position(cursor_position, cx)
 6327                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6328                    {
 6329                        return;
 6330                    }
 6331
 6332                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6333                    let mut write_ranges = Vec::new();
 6334                    let mut read_ranges = Vec::new();
 6335                    for highlight in highlights {
 6336                        for (excerpt_id, excerpt_range) in
 6337                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6338                        {
 6339                            let start = highlight
 6340                                .range
 6341                                .start
 6342                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6343                            let end = highlight
 6344                                .range
 6345                                .end
 6346                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6347                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6348                                continue;
 6349                            }
 6350
 6351                            let range = Anchor {
 6352                                buffer_id,
 6353                                excerpt_id,
 6354                                text_anchor: start,
 6355                                diff_base_anchor: None,
 6356                            }..Anchor {
 6357                                buffer_id,
 6358                                excerpt_id,
 6359                                text_anchor: end,
 6360                                diff_base_anchor: None,
 6361                            };
 6362                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6363                                write_ranges.push(range);
 6364                            } else {
 6365                                read_ranges.push(range);
 6366                            }
 6367                        }
 6368                    }
 6369
 6370                    this.highlight_background::<DocumentHighlightRead>(
 6371                        &read_ranges,
 6372                        |theme| theme.editor_document_highlight_read_background,
 6373                        cx,
 6374                    );
 6375                    this.highlight_background::<DocumentHighlightWrite>(
 6376                        &write_ranges,
 6377                        |theme| theme.editor_document_highlight_write_background,
 6378                        cx,
 6379                    );
 6380                    cx.notify();
 6381                })
 6382                .log_err();
 6383            }
 6384        }));
 6385        None
 6386    }
 6387
 6388    fn prepare_highlight_query_from_selection(
 6389        &mut self,
 6390        cx: &mut Context<Editor>,
 6391    ) -> Option<(String, Range<Anchor>)> {
 6392        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6393            return None;
 6394        }
 6395        if !EditorSettings::get_global(cx).selection_highlight {
 6396            return None;
 6397        }
 6398        if self.selections.count() != 1 || self.selections.line_mode {
 6399            return None;
 6400        }
 6401        let selection = self.selections.newest::<Point>(cx);
 6402        if selection.is_empty() || selection.start.row != selection.end.row {
 6403            return None;
 6404        }
 6405        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6406        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6407        let query = multi_buffer_snapshot
 6408            .text_for_range(selection_anchor_range.clone())
 6409            .collect::<String>();
 6410        if query.trim().is_empty() {
 6411            return None;
 6412        }
 6413        Some((query, selection_anchor_range))
 6414    }
 6415
 6416    fn update_selection_occurrence_highlights(
 6417        &mut self,
 6418        query_text: String,
 6419        query_range: Range<Anchor>,
 6420        multi_buffer_range_to_query: Range<Point>,
 6421        use_debounce: bool,
 6422        window: &mut Window,
 6423        cx: &mut Context<Editor>,
 6424    ) -> Task<()> {
 6425        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6426        cx.spawn_in(window, async move |editor, cx| {
 6427            if use_debounce {
 6428                cx.background_executor()
 6429                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6430                    .await;
 6431            }
 6432            let match_task = cx.background_spawn(async move {
 6433                let buffer_ranges = multi_buffer_snapshot
 6434                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6435                    .into_iter()
 6436                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6437                let mut match_ranges = Vec::new();
 6438                let Ok(regex) = project::search::SearchQuery::text(
 6439                    query_text.clone(),
 6440                    false,
 6441                    false,
 6442                    false,
 6443                    Default::default(),
 6444                    Default::default(),
 6445                    false,
 6446                    None,
 6447                ) else {
 6448                    return Vec::default();
 6449                };
 6450                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6451                    match_ranges.extend(
 6452                        regex
 6453                            .search(&buffer_snapshot, Some(search_range.clone()))
 6454                            .await
 6455                            .into_iter()
 6456                            .filter_map(|match_range| {
 6457                                let match_start = buffer_snapshot
 6458                                    .anchor_after(search_range.start + match_range.start);
 6459                                let match_end = buffer_snapshot
 6460                                    .anchor_before(search_range.start + match_range.end);
 6461                                let match_anchor_range = Anchor::range_in_buffer(
 6462                                    excerpt_id,
 6463                                    buffer_snapshot.remote_id(),
 6464                                    match_start..match_end,
 6465                                );
 6466                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6467                            }),
 6468                    );
 6469                }
 6470                match_ranges
 6471            });
 6472            let match_ranges = match_task.await;
 6473            editor
 6474                .update_in(cx, |editor, _, cx| {
 6475                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6476                    if !match_ranges.is_empty() {
 6477                        editor.highlight_background::<SelectedTextHighlight>(
 6478                            &match_ranges,
 6479                            |theme| theme.editor_document_highlight_bracket_background,
 6480                            cx,
 6481                        )
 6482                    }
 6483                })
 6484                .log_err();
 6485        })
 6486    }
 6487
 6488    fn refresh_selected_text_highlights(
 6489        &mut self,
 6490        on_buffer_edit: bool,
 6491        window: &mut Window,
 6492        cx: &mut Context<Editor>,
 6493    ) {
 6494        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6495        else {
 6496            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6497            self.quick_selection_highlight_task.take();
 6498            self.debounced_selection_highlight_task.take();
 6499            return;
 6500        };
 6501        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6502        if on_buffer_edit
 6503            || self
 6504                .quick_selection_highlight_task
 6505                .as_ref()
 6506                .map_or(true, |(prev_anchor_range, _)| {
 6507                    prev_anchor_range != &query_range
 6508                })
 6509        {
 6510            let multi_buffer_visible_start = self
 6511                .scroll_manager
 6512                .anchor()
 6513                .anchor
 6514                .to_point(&multi_buffer_snapshot);
 6515            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6516                multi_buffer_visible_start
 6517                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6518                Bias::Left,
 6519            );
 6520            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6521            self.quick_selection_highlight_task = Some((
 6522                query_range.clone(),
 6523                self.update_selection_occurrence_highlights(
 6524                    query_text.clone(),
 6525                    query_range.clone(),
 6526                    multi_buffer_visible_range,
 6527                    false,
 6528                    window,
 6529                    cx,
 6530                ),
 6531            ));
 6532        }
 6533        if on_buffer_edit
 6534            || self
 6535                .debounced_selection_highlight_task
 6536                .as_ref()
 6537                .map_or(true, |(prev_anchor_range, _)| {
 6538                    prev_anchor_range != &query_range
 6539                })
 6540        {
 6541            let multi_buffer_start = multi_buffer_snapshot
 6542                .anchor_before(0)
 6543                .to_point(&multi_buffer_snapshot);
 6544            let multi_buffer_end = multi_buffer_snapshot
 6545                .anchor_after(multi_buffer_snapshot.len())
 6546                .to_point(&multi_buffer_snapshot);
 6547            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6548            self.debounced_selection_highlight_task = Some((
 6549                query_range.clone(),
 6550                self.update_selection_occurrence_highlights(
 6551                    query_text,
 6552                    query_range,
 6553                    multi_buffer_full_range,
 6554                    true,
 6555                    window,
 6556                    cx,
 6557                ),
 6558            ));
 6559        }
 6560    }
 6561
 6562    pub fn refresh_inline_completion(
 6563        &mut self,
 6564        debounce: bool,
 6565        user_requested: bool,
 6566        window: &mut Window,
 6567        cx: &mut Context<Self>,
 6568    ) -> Option<()> {
 6569        let provider = self.edit_prediction_provider()?;
 6570        let cursor = self.selections.newest_anchor().head();
 6571        let (buffer, cursor_buffer_position) =
 6572            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6573
 6574        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6575            self.discard_inline_completion(false, cx);
 6576            return None;
 6577        }
 6578
 6579        if !user_requested
 6580            && (!self.should_show_edit_predictions()
 6581                || !self.is_focused(window)
 6582                || buffer.read(cx).is_empty())
 6583        {
 6584            self.discard_inline_completion(false, cx);
 6585            return None;
 6586        }
 6587
 6588        self.update_visible_inline_completion(window, cx);
 6589        provider.refresh(
 6590            self.project.clone(),
 6591            buffer,
 6592            cursor_buffer_position,
 6593            debounce,
 6594            cx,
 6595        );
 6596        Some(())
 6597    }
 6598
 6599    fn show_edit_predictions_in_menu(&self) -> bool {
 6600        match self.edit_prediction_settings {
 6601            EditPredictionSettings::Disabled => false,
 6602            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6603        }
 6604    }
 6605
 6606    pub fn edit_predictions_enabled(&self) -> bool {
 6607        match self.edit_prediction_settings {
 6608            EditPredictionSettings::Disabled => false,
 6609            EditPredictionSettings::Enabled { .. } => true,
 6610        }
 6611    }
 6612
 6613    fn edit_prediction_requires_modifier(&self) -> bool {
 6614        match self.edit_prediction_settings {
 6615            EditPredictionSettings::Disabled => false,
 6616            EditPredictionSettings::Enabled {
 6617                preview_requires_modifier,
 6618                ..
 6619            } => preview_requires_modifier,
 6620        }
 6621    }
 6622
 6623    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6624        if self.edit_prediction_provider.is_none() {
 6625            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6626        } else {
 6627            let selection = self.selections.newest_anchor();
 6628            let cursor = selection.head();
 6629
 6630            if let Some((buffer, cursor_buffer_position)) =
 6631                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6632            {
 6633                self.edit_prediction_settings =
 6634                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6635            }
 6636        }
 6637    }
 6638
 6639    fn edit_prediction_settings_at_position(
 6640        &self,
 6641        buffer: &Entity<Buffer>,
 6642        buffer_position: language::Anchor,
 6643        cx: &App,
 6644    ) -> EditPredictionSettings {
 6645        if !self.mode.is_full()
 6646            || !self.show_inline_completions_override.unwrap_or(true)
 6647            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6648        {
 6649            return EditPredictionSettings::Disabled;
 6650        }
 6651
 6652        let buffer = buffer.read(cx);
 6653
 6654        let file = buffer.file();
 6655
 6656        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6657            return EditPredictionSettings::Disabled;
 6658        };
 6659
 6660        let by_provider = matches!(
 6661            self.menu_inline_completions_policy,
 6662            MenuInlineCompletionsPolicy::ByProvider
 6663        );
 6664
 6665        let show_in_menu = by_provider
 6666            && self
 6667                .edit_prediction_provider
 6668                .as_ref()
 6669                .map_or(false, |provider| {
 6670                    provider.provider.show_completions_in_menu()
 6671                });
 6672
 6673        let preview_requires_modifier =
 6674            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6675
 6676        EditPredictionSettings::Enabled {
 6677            show_in_menu,
 6678            preview_requires_modifier,
 6679        }
 6680    }
 6681
 6682    fn should_show_edit_predictions(&self) -> bool {
 6683        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6684    }
 6685
 6686    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6687        matches!(
 6688            self.edit_prediction_preview,
 6689            EditPredictionPreview::Active { .. }
 6690        )
 6691    }
 6692
 6693    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6694        let cursor = self.selections.newest_anchor().head();
 6695        if let Some((buffer, cursor_position)) =
 6696            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6697        {
 6698            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6699        } else {
 6700            false
 6701        }
 6702    }
 6703
 6704    pub fn supports_minimap(&self, cx: &App) -> bool {
 6705        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6706    }
 6707
 6708    fn edit_predictions_enabled_in_buffer(
 6709        &self,
 6710        buffer: &Entity<Buffer>,
 6711        buffer_position: language::Anchor,
 6712        cx: &App,
 6713    ) -> bool {
 6714        maybe!({
 6715            if self.read_only(cx) {
 6716                return Some(false);
 6717            }
 6718            let provider = self.edit_prediction_provider()?;
 6719            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6720                return Some(false);
 6721            }
 6722            let buffer = buffer.read(cx);
 6723            let Some(file) = buffer.file() else {
 6724                return Some(true);
 6725            };
 6726            let settings = all_language_settings(Some(file), cx);
 6727            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6728        })
 6729        .unwrap_or(false)
 6730    }
 6731
 6732    fn cycle_inline_completion(
 6733        &mut self,
 6734        direction: Direction,
 6735        window: &mut Window,
 6736        cx: &mut Context<Self>,
 6737    ) -> Option<()> {
 6738        let provider = self.edit_prediction_provider()?;
 6739        let cursor = self.selections.newest_anchor().head();
 6740        let (buffer, cursor_buffer_position) =
 6741            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6742        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6743            return None;
 6744        }
 6745
 6746        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6747        self.update_visible_inline_completion(window, cx);
 6748
 6749        Some(())
 6750    }
 6751
 6752    pub fn show_inline_completion(
 6753        &mut self,
 6754        _: &ShowEditPrediction,
 6755        window: &mut Window,
 6756        cx: &mut Context<Self>,
 6757    ) {
 6758        if !self.has_active_inline_completion() {
 6759            self.refresh_inline_completion(false, true, window, cx);
 6760            return;
 6761        }
 6762
 6763        self.update_visible_inline_completion(window, cx);
 6764    }
 6765
 6766    pub fn display_cursor_names(
 6767        &mut self,
 6768        _: &DisplayCursorNames,
 6769        window: &mut Window,
 6770        cx: &mut Context<Self>,
 6771    ) {
 6772        self.show_cursor_names(window, cx);
 6773    }
 6774
 6775    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6776        self.show_cursor_names = true;
 6777        cx.notify();
 6778        cx.spawn_in(window, async move |this, cx| {
 6779            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6780            this.update(cx, |this, cx| {
 6781                this.show_cursor_names = false;
 6782                cx.notify()
 6783            })
 6784            .ok()
 6785        })
 6786        .detach();
 6787    }
 6788
 6789    pub fn next_edit_prediction(
 6790        &mut self,
 6791        _: &NextEditPrediction,
 6792        window: &mut Window,
 6793        cx: &mut Context<Self>,
 6794    ) {
 6795        if self.has_active_inline_completion() {
 6796            self.cycle_inline_completion(Direction::Next, window, cx);
 6797        } else {
 6798            let is_copilot_disabled = self
 6799                .refresh_inline_completion(false, true, window, cx)
 6800                .is_none();
 6801            if is_copilot_disabled {
 6802                cx.propagate();
 6803            }
 6804        }
 6805    }
 6806
 6807    pub fn previous_edit_prediction(
 6808        &mut self,
 6809        _: &PreviousEditPrediction,
 6810        window: &mut Window,
 6811        cx: &mut Context<Self>,
 6812    ) {
 6813        if self.has_active_inline_completion() {
 6814            self.cycle_inline_completion(Direction::Prev, window, cx);
 6815        } else {
 6816            let is_copilot_disabled = self
 6817                .refresh_inline_completion(false, true, window, cx)
 6818                .is_none();
 6819            if is_copilot_disabled {
 6820                cx.propagate();
 6821            }
 6822        }
 6823    }
 6824
 6825    pub fn accept_edit_prediction(
 6826        &mut self,
 6827        _: &AcceptEditPrediction,
 6828        window: &mut Window,
 6829        cx: &mut Context<Self>,
 6830    ) {
 6831        if self.show_edit_predictions_in_menu() {
 6832            self.hide_context_menu(window, cx);
 6833        }
 6834
 6835        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6836            return;
 6837        };
 6838
 6839        self.report_inline_completion_event(
 6840            active_inline_completion.completion_id.clone(),
 6841            true,
 6842            cx,
 6843        );
 6844
 6845        match &active_inline_completion.completion {
 6846            InlineCompletion::Move { target, .. } => {
 6847                let target = *target;
 6848
 6849                if let Some(position_map) = &self.last_position_map {
 6850                    if position_map
 6851                        .visible_row_range
 6852                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6853                        || !self.edit_prediction_requires_modifier()
 6854                    {
 6855                        self.unfold_ranges(&[target..target], true, false, cx);
 6856                        // Note that this is also done in vim's handler of the Tab action.
 6857                        self.change_selections(
 6858                            Some(Autoscroll::newest()),
 6859                            window,
 6860                            cx,
 6861                            |selections| {
 6862                                selections.select_anchor_ranges([target..target]);
 6863                            },
 6864                        );
 6865                        self.clear_row_highlights::<EditPredictionPreview>();
 6866
 6867                        self.edit_prediction_preview
 6868                            .set_previous_scroll_position(None);
 6869                    } else {
 6870                        self.edit_prediction_preview
 6871                            .set_previous_scroll_position(Some(
 6872                                position_map.snapshot.scroll_anchor,
 6873                            ));
 6874
 6875                        self.highlight_rows::<EditPredictionPreview>(
 6876                            target..target,
 6877                            cx.theme().colors().editor_highlighted_line_background,
 6878                            RowHighlightOptions {
 6879                                autoscroll: true,
 6880                                ..Default::default()
 6881                            },
 6882                            cx,
 6883                        );
 6884                        self.request_autoscroll(Autoscroll::fit(), cx);
 6885                    }
 6886                }
 6887            }
 6888            InlineCompletion::Edit { edits, .. } => {
 6889                if let Some(provider) = self.edit_prediction_provider() {
 6890                    provider.accept(cx);
 6891                }
 6892
 6893                // Store the transaction ID and selections before applying the edit
 6894                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6895
 6896                let snapshot = self.buffer.read(cx).snapshot(cx);
 6897                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6898
 6899                self.buffer.update(cx, |buffer, cx| {
 6900                    buffer.edit(edits.iter().cloned(), None, cx)
 6901                });
 6902
 6903                self.change_selections(None, window, cx, |s| {
 6904                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6905                });
 6906
 6907                let selections = self.selections.disjoint_anchors();
 6908                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6909                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6910                    if has_new_transaction {
 6911                        self.selection_history
 6912                            .insert_transaction(transaction_id_now, selections);
 6913                    }
 6914                }
 6915
 6916                self.update_visible_inline_completion(window, cx);
 6917                if self.active_inline_completion.is_none() {
 6918                    self.refresh_inline_completion(true, true, window, cx);
 6919                }
 6920
 6921                cx.notify();
 6922            }
 6923        }
 6924
 6925        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6926    }
 6927
 6928    pub fn accept_partial_inline_completion(
 6929        &mut self,
 6930        _: &AcceptPartialEditPrediction,
 6931        window: &mut Window,
 6932        cx: &mut Context<Self>,
 6933    ) {
 6934        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6935            return;
 6936        };
 6937        if self.selections.count() != 1 {
 6938            return;
 6939        }
 6940
 6941        self.report_inline_completion_event(
 6942            active_inline_completion.completion_id.clone(),
 6943            true,
 6944            cx,
 6945        );
 6946
 6947        match &active_inline_completion.completion {
 6948            InlineCompletion::Move { target, .. } => {
 6949                let target = *target;
 6950                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6951                    selections.select_anchor_ranges([target..target]);
 6952                });
 6953            }
 6954            InlineCompletion::Edit { edits, .. } => {
 6955                // Find an insertion that starts at the cursor position.
 6956                let snapshot = self.buffer.read(cx).snapshot(cx);
 6957                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6958                let insertion = edits.iter().find_map(|(range, text)| {
 6959                    let range = range.to_offset(&snapshot);
 6960                    if range.is_empty() && range.start == cursor_offset {
 6961                        Some(text)
 6962                    } else {
 6963                        None
 6964                    }
 6965                });
 6966
 6967                if let Some(text) = insertion {
 6968                    let mut partial_completion = text
 6969                        .chars()
 6970                        .by_ref()
 6971                        .take_while(|c| c.is_alphabetic())
 6972                        .collect::<String>();
 6973                    if partial_completion.is_empty() {
 6974                        partial_completion = text
 6975                            .chars()
 6976                            .by_ref()
 6977                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6978                            .collect::<String>();
 6979                    }
 6980
 6981                    cx.emit(EditorEvent::InputHandled {
 6982                        utf16_range_to_replace: None,
 6983                        text: partial_completion.clone().into(),
 6984                    });
 6985
 6986                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6987
 6988                    self.refresh_inline_completion(true, true, window, cx);
 6989                    cx.notify();
 6990                } else {
 6991                    self.accept_edit_prediction(&Default::default(), window, cx);
 6992                }
 6993            }
 6994        }
 6995    }
 6996
 6997    fn discard_inline_completion(
 6998        &mut self,
 6999        should_report_inline_completion_event: bool,
 7000        cx: &mut Context<Self>,
 7001    ) -> bool {
 7002        if should_report_inline_completion_event {
 7003            let completion_id = self
 7004                .active_inline_completion
 7005                .as_ref()
 7006                .and_then(|active_completion| active_completion.completion_id.clone());
 7007
 7008            self.report_inline_completion_event(completion_id, false, cx);
 7009        }
 7010
 7011        if let Some(provider) = self.edit_prediction_provider() {
 7012            provider.discard(cx);
 7013        }
 7014
 7015        self.take_active_inline_completion(cx)
 7016    }
 7017
 7018    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7019        let Some(provider) = self.edit_prediction_provider() else {
 7020            return;
 7021        };
 7022
 7023        let Some((_, buffer, _)) = self
 7024            .buffer
 7025            .read(cx)
 7026            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7027        else {
 7028            return;
 7029        };
 7030
 7031        let extension = buffer
 7032            .read(cx)
 7033            .file()
 7034            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7035
 7036        let event_type = match accepted {
 7037            true => "Edit Prediction Accepted",
 7038            false => "Edit Prediction Discarded",
 7039        };
 7040        telemetry::event!(
 7041            event_type,
 7042            provider = provider.name(),
 7043            prediction_id = id,
 7044            suggestion_accepted = accepted,
 7045            file_extension = extension,
 7046        );
 7047    }
 7048
 7049    pub fn has_active_inline_completion(&self) -> bool {
 7050        self.active_inline_completion.is_some()
 7051    }
 7052
 7053    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7054        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7055            return false;
 7056        };
 7057
 7058        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7059        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7060        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7061        true
 7062    }
 7063
 7064    /// Returns true when we're displaying the edit prediction popover below the cursor
 7065    /// like we are not previewing and the LSP autocomplete menu is visible
 7066    /// or we are in `when_holding_modifier` mode.
 7067    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7068        if self.edit_prediction_preview_is_active()
 7069            || !self.show_edit_predictions_in_menu()
 7070            || !self.edit_predictions_enabled()
 7071        {
 7072            return false;
 7073        }
 7074
 7075        if self.has_visible_completions_menu() {
 7076            return true;
 7077        }
 7078
 7079        has_completion && self.edit_prediction_requires_modifier()
 7080    }
 7081
 7082    fn handle_modifiers_changed(
 7083        &mut self,
 7084        modifiers: Modifiers,
 7085        position_map: &PositionMap,
 7086        window: &mut Window,
 7087        cx: &mut Context<Self>,
 7088    ) {
 7089        if self.show_edit_predictions_in_menu() {
 7090            self.update_edit_prediction_preview(&modifiers, window, cx);
 7091        }
 7092
 7093        self.update_selection_mode(&modifiers, position_map, window, cx);
 7094
 7095        let mouse_position = window.mouse_position();
 7096        if !position_map.text_hitbox.is_hovered(window) {
 7097            return;
 7098        }
 7099
 7100        self.update_hovered_link(
 7101            position_map.point_for_position(mouse_position),
 7102            &position_map.snapshot,
 7103            modifiers,
 7104            window,
 7105            cx,
 7106        )
 7107    }
 7108
 7109    fn multi_cursor_modifier(
 7110        cursor_event: bool,
 7111        modifiers: &Modifiers,
 7112        cx: &mut Context<Self>,
 7113    ) -> bool {
 7114        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7115        if cursor_event {
 7116            match multi_cursor_setting {
 7117                MultiCursorModifier::Alt => modifiers.alt,
 7118                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7119            }
 7120        } else {
 7121            match multi_cursor_setting {
 7122                MultiCursorModifier::Alt => modifiers.secondary(),
 7123                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7124            }
 7125        }
 7126    }
 7127
 7128    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7129        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7130    }
 7131
 7132    fn update_selection_mode(
 7133        &mut self,
 7134        modifiers: &Modifiers,
 7135        position_map: &PositionMap,
 7136        window: &mut Window,
 7137        cx: &mut Context<Self>,
 7138    ) {
 7139        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7140        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7141            || self.selections.pending.is_none()
 7142        {
 7143            return;
 7144        }
 7145
 7146        let mouse_position = window.mouse_position();
 7147        let point_for_position = position_map.point_for_position(mouse_position);
 7148        let position = point_for_position.previous_valid;
 7149
 7150        self.select(
 7151            SelectPhase::BeginColumnar {
 7152                position,
 7153                reset: false,
 7154                goal_column: point_for_position.exact_unclipped.column(),
 7155            },
 7156            window,
 7157            cx,
 7158        );
 7159    }
 7160
 7161    fn update_edit_prediction_preview(
 7162        &mut self,
 7163        modifiers: &Modifiers,
 7164        window: &mut Window,
 7165        cx: &mut Context<Self>,
 7166    ) {
 7167        let mut modifiers_held = false;
 7168        if let Some(accept_keystroke) = self
 7169            .accept_edit_prediction_keybind(false, window, cx)
 7170            .keystroke()
 7171        {
 7172            modifiers_held = modifiers_held
 7173                || (&accept_keystroke.modifiers == modifiers
 7174                    && accept_keystroke.modifiers.modified());
 7175        };
 7176        if let Some(accept_partial_keystroke) = self
 7177            .accept_edit_prediction_keybind(true, window, cx)
 7178            .keystroke()
 7179        {
 7180            modifiers_held = modifiers_held
 7181                || (&accept_partial_keystroke.modifiers == modifiers
 7182                    && accept_partial_keystroke.modifiers.modified());
 7183        }
 7184
 7185        if modifiers_held {
 7186            if matches!(
 7187                self.edit_prediction_preview,
 7188                EditPredictionPreview::Inactive { .. }
 7189            ) {
 7190                self.edit_prediction_preview = EditPredictionPreview::Active {
 7191                    previous_scroll_position: None,
 7192                    since: Instant::now(),
 7193                };
 7194
 7195                self.update_visible_inline_completion(window, cx);
 7196                cx.notify();
 7197            }
 7198        } else if let EditPredictionPreview::Active {
 7199            previous_scroll_position,
 7200            since,
 7201        } = self.edit_prediction_preview
 7202        {
 7203            if let (Some(previous_scroll_position), Some(position_map)) =
 7204                (previous_scroll_position, self.last_position_map.as_ref())
 7205            {
 7206                self.set_scroll_position(
 7207                    previous_scroll_position
 7208                        .scroll_position(&position_map.snapshot.display_snapshot),
 7209                    window,
 7210                    cx,
 7211                );
 7212            }
 7213
 7214            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7215                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7216            };
 7217            self.clear_row_highlights::<EditPredictionPreview>();
 7218            self.update_visible_inline_completion(window, cx);
 7219            cx.notify();
 7220        }
 7221    }
 7222
 7223    fn update_visible_inline_completion(
 7224        &mut self,
 7225        _window: &mut Window,
 7226        cx: &mut Context<Self>,
 7227    ) -> Option<()> {
 7228        let selection = self.selections.newest_anchor();
 7229        let cursor = selection.head();
 7230        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7231        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7232        let excerpt_id = cursor.excerpt_id;
 7233
 7234        let show_in_menu = self.show_edit_predictions_in_menu();
 7235        let completions_menu_has_precedence = !show_in_menu
 7236            && (self.context_menu.borrow().is_some()
 7237                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7238
 7239        if completions_menu_has_precedence
 7240            || !offset_selection.is_empty()
 7241            || self
 7242                .active_inline_completion
 7243                .as_ref()
 7244                .map_or(false, |completion| {
 7245                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7246                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7247                    !invalidation_range.contains(&offset_selection.head())
 7248                })
 7249        {
 7250            self.discard_inline_completion(false, cx);
 7251            return None;
 7252        }
 7253
 7254        self.take_active_inline_completion(cx);
 7255        let Some(provider) = self.edit_prediction_provider() else {
 7256            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7257            return None;
 7258        };
 7259
 7260        let (buffer, cursor_buffer_position) =
 7261            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7262
 7263        self.edit_prediction_settings =
 7264            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7265
 7266        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7267
 7268        if self.edit_prediction_indent_conflict {
 7269            let cursor_point = cursor.to_point(&multibuffer);
 7270
 7271            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7272
 7273            if let Some((_, indent)) = indents.iter().next() {
 7274                if indent.len == cursor_point.column {
 7275                    self.edit_prediction_indent_conflict = false;
 7276                }
 7277            }
 7278        }
 7279
 7280        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7281        let edits = inline_completion
 7282            .edits
 7283            .into_iter()
 7284            .flat_map(|(range, new_text)| {
 7285                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7286                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7287                Some((start..end, new_text))
 7288            })
 7289            .collect::<Vec<_>>();
 7290        if edits.is_empty() {
 7291            return None;
 7292        }
 7293
 7294        let first_edit_start = edits.first().unwrap().0.start;
 7295        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7296        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7297
 7298        let last_edit_end = edits.last().unwrap().0.end;
 7299        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7300        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7301
 7302        let cursor_row = cursor.to_point(&multibuffer).row;
 7303
 7304        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7305
 7306        let mut inlay_ids = Vec::new();
 7307        let invalidation_row_range;
 7308        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7309            Some(cursor_row..edit_end_row)
 7310        } else if cursor_row > edit_end_row {
 7311            Some(edit_start_row..cursor_row)
 7312        } else {
 7313            None
 7314        };
 7315        let is_move =
 7316            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7317        let completion = if is_move {
 7318            invalidation_row_range =
 7319                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7320            let target = first_edit_start;
 7321            InlineCompletion::Move { target, snapshot }
 7322        } else {
 7323            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7324                && !self.inline_completions_hidden_for_vim_mode;
 7325
 7326            if show_completions_in_buffer {
 7327                if edits
 7328                    .iter()
 7329                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7330                {
 7331                    let mut inlays = Vec::new();
 7332                    for (range, new_text) in &edits {
 7333                        let inlay = Inlay::inline_completion(
 7334                            post_inc(&mut self.next_inlay_id),
 7335                            range.start,
 7336                            new_text.as_str(),
 7337                        );
 7338                        inlay_ids.push(inlay.id);
 7339                        inlays.push(inlay);
 7340                    }
 7341
 7342                    self.splice_inlays(&[], inlays, cx);
 7343                } else {
 7344                    let background_color = cx.theme().status().deleted_background;
 7345                    self.highlight_text::<InlineCompletionHighlight>(
 7346                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7347                        HighlightStyle {
 7348                            background_color: Some(background_color),
 7349                            ..Default::default()
 7350                        },
 7351                        cx,
 7352                    );
 7353                }
 7354            }
 7355
 7356            invalidation_row_range = edit_start_row..edit_end_row;
 7357
 7358            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7359                if provider.show_tab_accept_marker() {
 7360                    EditDisplayMode::TabAccept
 7361                } else {
 7362                    EditDisplayMode::Inline
 7363                }
 7364            } else {
 7365                EditDisplayMode::DiffPopover
 7366            };
 7367
 7368            InlineCompletion::Edit {
 7369                edits,
 7370                edit_preview: inline_completion.edit_preview,
 7371                display_mode,
 7372                snapshot,
 7373            }
 7374        };
 7375
 7376        let invalidation_range = multibuffer
 7377            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7378            ..multibuffer.anchor_after(Point::new(
 7379                invalidation_row_range.end,
 7380                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7381            ));
 7382
 7383        self.stale_inline_completion_in_menu = None;
 7384        self.active_inline_completion = Some(InlineCompletionState {
 7385            inlay_ids,
 7386            completion,
 7387            completion_id: inline_completion.id,
 7388            invalidation_range,
 7389        });
 7390
 7391        cx.notify();
 7392
 7393        Some(())
 7394    }
 7395
 7396    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7397        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7398    }
 7399
 7400    fn clear_tasks(&mut self) {
 7401        self.tasks.clear()
 7402    }
 7403
 7404    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7405        if self.tasks.insert(key, value).is_some() {
 7406            // This case should hopefully be rare, but just in case...
 7407            log::error!(
 7408                "multiple different run targets found on a single line, only the last target will be rendered"
 7409            )
 7410        }
 7411    }
 7412
 7413    /// Get all display points of breakpoints that will be rendered within editor
 7414    ///
 7415    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7416    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7417    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7418    fn active_breakpoints(
 7419        &self,
 7420        range: Range<DisplayRow>,
 7421        window: &mut Window,
 7422        cx: &mut Context<Self>,
 7423    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7424        let mut breakpoint_display_points = HashMap::default();
 7425
 7426        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7427            return breakpoint_display_points;
 7428        };
 7429
 7430        let snapshot = self.snapshot(window, cx);
 7431
 7432        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7433        let Some(project) = self.project.as_ref() else {
 7434            return breakpoint_display_points;
 7435        };
 7436
 7437        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7438            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7439
 7440        for (buffer_snapshot, range, excerpt_id) in
 7441            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7442        {
 7443            let Some(buffer) = project
 7444                .read(cx)
 7445                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7446            else {
 7447                continue;
 7448            };
 7449            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7450                &buffer,
 7451                Some(
 7452                    buffer_snapshot.anchor_before(range.start)
 7453                        ..buffer_snapshot.anchor_after(range.end),
 7454                ),
 7455                buffer_snapshot,
 7456                cx,
 7457            );
 7458            for (breakpoint, state) in breakpoints {
 7459                let multi_buffer_anchor =
 7460                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7461                let position = multi_buffer_anchor
 7462                    .to_point(&multi_buffer_snapshot)
 7463                    .to_display_point(&snapshot);
 7464
 7465                breakpoint_display_points.insert(
 7466                    position.row(),
 7467                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7468                );
 7469            }
 7470        }
 7471
 7472        breakpoint_display_points
 7473    }
 7474
 7475    fn breakpoint_context_menu(
 7476        &self,
 7477        anchor: Anchor,
 7478        window: &mut Window,
 7479        cx: &mut Context<Self>,
 7480    ) -> Entity<ui::ContextMenu> {
 7481        let weak_editor = cx.weak_entity();
 7482        let focus_handle = self.focus_handle(cx);
 7483
 7484        let row = self
 7485            .buffer
 7486            .read(cx)
 7487            .snapshot(cx)
 7488            .summary_for_anchor::<Point>(&anchor)
 7489            .row;
 7490
 7491        let breakpoint = self
 7492            .breakpoint_at_row(row, window, cx)
 7493            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7494
 7495        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7496            "Edit Log Breakpoint"
 7497        } else {
 7498            "Set Log Breakpoint"
 7499        };
 7500
 7501        let condition_breakpoint_msg = if breakpoint
 7502            .as_ref()
 7503            .is_some_and(|bp| bp.1.condition.is_some())
 7504        {
 7505            "Edit Condition Breakpoint"
 7506        } else {
 7507            "Set Condition Breakpoint"
 7508        };
 7509
 7510        let hit_condition_breakpoint_msg = if breakpoint
 7511            .as_ref()
 7512            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7513        {
 7514            "Edit Hit Condition Breakpoint"
 7515        } else {
 7516            "Set Hit Condition Breakpoint"
 7517        };
 7518
 7519        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7520            "Unset Breakpoint"
 7521        } else {
 7522            "Set Breakpoint"
 7523        };
 7524
 7525        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7526            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7527
 7528        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7529            BreakpointState::Enabled => Some("Disable"),
 7530            BreakpointState::Disabled => Some("Enable"),
 7531        });
 7532
 7533        let (anchor, breakpoint) =
 7534            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7535
 7536        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7537            menu.on_blur_subscription(Subscription::new(|| {}))
 7538                .context(focus_handle)
 7539                .when(run_to_cursor, |this| {
 7540                    let weak_editor = weak_editor.clone();
 7541                    this.entry("Run to cursor", None, move |window, cx| {
 7542                        weak_editor
 7543                            .update(cx, |editor, cx| {
 7544                                editor.change_selections(None, window, cx, |s| {
 7545                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7546                                });
 7547                            })
 7548                            .ok();
 7549
 7550                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7551                    })
 7552                    .separator()
 7553                })
 7554                .when_some(toggle_state_msg, |this, msg| {
 7555                    this.entry(msg, None, {
 7556                        let weak_editor = weak_editor.clone();
 7557                        let breakpoint = breakpoint.clone();
 7558                        move |_window, cx| {
 7559                            weak_editor
 7560                                .update(cx, |this, cx| {
 7561                                    this.edit_breakpoint_at_anchor(
 7562                                        anchor,
 7563                                        breakpoint.as_ref().clone(),
 7564                                        BreakpointEditAction::InvertState,
 7565                                        cx,
 7566                                    );
 7567                                })
 7568                                .log_err();
 7569                        }
 7570                    })
 7571                })
 7572                .entry(set_breakpoint_msg, None, {
 7573                    let weak_editor = weak_editor.clone();
 7574                    let breakpoint = breakpoint.clone();
 7575                    move |_window, cx| {
 7576                        weak_editor
 7577                            .update(cx, |this, cx| {
 7578                                this.edit_breakpoint_at_anchor(
 7579                                    anchor,
 7580                                    breakpoint.as_ref().clone(),
 7581                                    BreakpointEditAction::Toggle,
 7582                                    cx,
 7583                                );
 7584                            })
 7585                            .log_err();
 7586                    }
 7587                })
 7588                .entry(log_breakpoint_msg, None, {
 7589                    let breakpoint = breakpoint.clone();
 7590                    let weak_editor = weak_editor.clone();
 7591                    move |window, cx| {
 7592                        weak_editor
 7593                            .update(cx, |this, cx| {
 7594                                this.add_edit_breakpoint_block(
 7595                                    anchor,
 7596                                    breakpoint.as_ref(),
 7597                                    BreakpointPromptEditAction::Log,
 7598                                    window,
 7599                                    cx,
 7600                                );
 7601                            })
 7602                            .log_err();
 7603                    }
 7604                })
 7605                .entry(condition_breakpoint_msg, None, {
 7606                    let breakpoint = breakpoint.clone();
 7607                    let weak_editor = weak_editor.clone();
 7608                    move |window, cx| {
 7609                        weak_editor
 7610                            .update(cx, |this, cx| {
 7611                                this.add_edit_breakpoint_block(
 7612                                    anchor,
 7613                                    breakpoint.as_ref(),
 7614                                    BreakpointPromptEditAction::Condition,
 7615                                    window,
 7616                                    cx,
 7617                                );
 7618                            })
 7619                            .log_err();
 7620                    }
 7621                })
 7622                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7623                    weak_editor
 7624                        .update(cx, |this, cx| {
 7625                            this.add_edit_breakpoint_block(
 7626                                anchor,
 7627                                breakpoint.as_ref(),
 7628                                BreakpointPromptEditAction::HitCondition,
 7629                                window,
 7630                                cx,
 7631                            );
 7632                        })
 7633                        .log_err();
 7634                })
 7635        })
 7636    }
 7637
 7638    fn render_breakpoint(
 7639        &self,
 7640        position: Anchor,
 7641        row: DisplayRow,
 7642        breakpoint: &Breakpoint,
 7643        state: Option<BreakpointSessionState>,
 7644        cx: &mut Context<Self>,
 7645    ) -> IconButton {
 7646        let is_rejected = state.is_some_and(|s| !s.verified);
 7647        // Is it a breakpoint that shows up when hovering over gutter?
 7648        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7649            (false, false),
 7650            |PhantomBreakpointIndicator {
 7651                 is_active,
 7652                 display_row,
 7653                 collides_with_existing_breakpoint,
 7654             }| {
 7655                (
 7656                    is_active && display_row == row,
 7657                    collides_with_existing_breakpoint,
 7658                )
 7659            },
 7660        );
 7661
 7662        let (color, icon) = {
 7663            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7664                (false, false) => ui::IconName::DebugBreakpoint,
 7665                (true, false) => ui::IconName::DebugLogBreakpoint,
 7666                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7667                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7668            };
 7669
 7670            let color = if is_phantom {
 7671                Color::Hint
 7672            } else if is_rejected {
 7673                Color::Disabled
 7674            } else {
 7675                Color::Debugger
 7676            };
 7677
 7678            (color, icon)
 7679        };
 7680
 7681        let breakpoint = Arc::from(breakpoint.clone());
 7682
 7683        let alt_as_text = gpui::Keystroke {
 7684            modifiers: Modifiers::secondary_key(),
 7685            ..Default::default()
 7686        };
 7687        let primary_action_text = if breakpoint.is_disabled() {
 7688            "Enable breakpoint"
 7689        } else if is_phantom && !collides_with_existing {
 7690            "Set breakpoint"
 7691        } else {
 7692            "Unset breakpoint"
 7693        };
 7694        let focus_handle = self.focus_handle.clone();
 7695
 7696        let meta = if is_rejected {
 7697            SharedString::from("No executable code is associated with this line.")
 7698        } else if collides_with_existing && !breakpoint.is_disabled() {
 7699            SharedString::from(format!(
 7700                "{alt_as_text}-click to disable,\nright-click for more options."
 7701            ))
 7702        } else {
 7703            SharedString::from("Right-click for more options.")
 7704        };
 7705        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7706            .icon_size(IconSize::XSmall)
 7707            .size(ui::ButtonSize::None)
 7708            .when(is_rejected, |this| {
 7709                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7710            })
 7711            .icon_color(color)
 7712            .style(ButtonStyle::Transparent)
 7713            .on_click(cx.listener({
 7714                let breakpoint = breakpoint.clone();
 7715
 7716                move |editor, event: &ClickEvent, window, cx| {
 7717                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7718                        BreakpointEditAction::InvertState
 7719                    } else {
 7720                        BreakpointEditAction::Toggle
 7721                    };
 7722
 7723                    window.focus(&editor.focus_handle(cx));
 7724                    editor.edit_breakpoint_at_anchor(
 7725                        position,
 7726                        breakpoint.as_ref().clone(),
 7727                        edit_action,
 7728                        cx,
 7729                    );
 7730                }
 7731            }))
 7732            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7733                editor.set_breakpoint_context_menu(
 7734                    row,
 7735                    Some(position),
 7736                    event.down.position,
 7737                    window,
 7738                    cx,
 7739                );
 7740            }))
 7741            .tooltip(move |window, cx| {
 7742                Tooltip::with_meta_in(
 7743                    primary_action_text,
 7744                    Some(&ToggleBreakpoint),
 7745                    meta.clone(),
 7746                    &focus_handle,
 7747                    window,
 7748                    cx,
 7749                )
 7750            })
 7751    }
 7752
 7753    fn build_tasks_context(
 7754        project: &Entity<Project>,
 7755        buffer: &Entity<Buffer>,
 7756        buffer_row: u32,
 7757        tasks: &Arc<RunnableTasks>,
 7758        cx: &mut Context<Self>,
 7759    ) -> Task<Option<task::TaskContext>> {
 7760        let position = Point::new(buffer_row, tasks.column);
 7761        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7762        let location = Location {
 7763            buffer: buffer.clone(),
 7764            range: range_start..range_start,
 7765        };
 7766        // Fill in the environmental variables from the tree-sitter captures
 7767        let mut captured_task_variables = TaskVariables::default();
 7768        for (capture_name, value) in tasks.extra_variables.clone() {
 7769            captured_task_variables.insert(
 7770                task::VariableName::Custom(capture_name.into()),
 7771                value.clone(),
 7772            );
 7773        }
 7774        project.update(cx, |project, cx| {
 7775            project.task_store().update(cx, |task_store, cx| {
 7776                task_store.task_context_for_location(captured_task_variables, location, cx)
 7777            })
 7778        })
 7779    }
 7780
 7781    pub fn spawn_nearest_task(
 7782        &mut self,
 7783        action: &SpawnNearestTask,
 7784        window: &mut Window,
 7785        cx: &mut Context<Self>,
 7786    ) {
 7787        let Some((workspace, _)) = self.workspace.clone() else {
 7788            return;
 7789        };
 7790        let Some(project) = self.project.clone() else {
 7791            return;
 7792        };
 7793
 7794        // Try to find a closest, enclosing node using tree-sitter that has a
 7795        // task
 7796        let Some((buffer, buffer_row, tasks)) = self
 7797            .find_enclosing_node_task(cx)
 7798            // Or find the task that's closest in row-distance.
 7799            .or_else(|| self.find_closest_task(cx))
 7800        else {
 7801            return;
 7802        };
 7803
 7804        let reveal_strategy = action.reveal;
 7805        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7806        cx.spawn_in(window, async move |_, cx| {
 7807            let context = task_context.await?;
 7808            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7809
 7810            let resolved = &mut resolved_task.resolved;
 7811            resolved.reveal = reveal_strategy;
 7812
 7813            workspace
 7814                .update_in(cx, |workspace, window, cx| {
 7815                    workspace.schedule_resolved_task(
 7816                        task_source_kind,
 7817                        resolved_task,
 7818                        false,
 7819                        window,
 7820                        cx,
 7821                    );
 7822                })
 7823                .ok()
 7824        })
 7825        .detach();
 7826    }
 7827
 7828    fn find_closest_task(
 7829        &mut self,
 7830        cx: &mut Context<Self>,
 7831    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7832        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7833
 7834        let ((buffer_id, row), tasks) = self
 7835            .tasks
 7836            .iter()
 7837            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7838
 7839        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7840        let tasks = Arc::new(tasks.to_owned());
 7841        Some((buffer, *row, tasks))
 7842    }
 7843
 7844    fn find_enclosing_node_task(
 7845        &mut self,
 7846        cx: &mut Context<Self>,
 7847    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7848        let snapshot = self.buffer.read(cx).snapshot(cx);
 7849        let offset = self.selections.newest::<usize>(cx).head();
 7850        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7851        let buffer_id = excerpt.buffer().remote_id();
 7852
 7853        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7854        let mut cursor = layer.node().walk();
 7855
 7856        while cursor.goto_first_child_for_byte(offset).is_some() {
 7857            if cursor.node().end_byte() == offset {
 7858                cursor.goto_next_sibling();
 7859            }
 7860        }
 7861
 7862        // Ascend to the smallest ancestor that contains the range and has a task.
 7863        loop {
 7864            let node = cursor.node();
 7865            let node_range = node.byte_range();
 7866            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7867
 7868            // Check if this node contains our offset
 7869            if node_range.start <= offset && node_range.end >= offset {
 7870                // If it contains offset, check for task
 7871                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7872                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7873                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7874                }
 7875            }
 7876
 7877            if !cursor.goto_parent() {
 7878                break;
 7879            }
 7880        }
 7881        None
 7882    }
 7883
 7884    fn render_run_indicator(
 7885        &self,
 7886        _style: &EditorStyle,
 7887        is_active: bool,
 7888        row: DisplayRow,
 7889        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7890        cx: &mut Context<Self>,
 7891    ) -> IconButton {
 7892        let color = Color::Muted;
 7893        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7894
 7895        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7896            .shape(ui::IconButtonShape::Square)
 7897            .icon_size(IconSize::XSmall)
 7898            .icon_color(color)
 7899            .toggle_state(is_active)
 7900            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7901                let quick_launch = e.down.button == MouseButton::Left;
 7902                window.focus(&editor.focus_handle(cx));
 7903                editor.toggle_code_actions(
 7904                    &ToggleCodeActions {
 7905                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7906                        quick_launch,
 7907                    },
 7908                    window,
 7909                    cx,
 7910                );
 7911            }))
 7912            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7913                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7914            }))
 7915    }
 7916
 7917    pub fn context_menu_visible(&self) -> bool {
 7918        !self.edit_prediction_preview_is_active()
 7919            && self
 7920                .context_menu
 7921                .borrow()
 7922                .as_ref()
 7923                .map_or(false, |menu| menu.visible())
 7924    }
 7925
 7926    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7927        self.context_menu
 7928            .borrow()
 7929            .as_ref()
 7930            .map(|menu| menu.origin())
 7931    }
 7932
 7933    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7934        self.context_menu_options = Some(options);
 7935    }
 7936
 7937    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7938    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7939
 7940    fn render_edit_prediction_popover(
 7941        &mut self,
 7942        text_bounds: &Bounds<Pixels>,
 7943        content_origin: gpui::Point<Pixels>,
 7944        right_margin: Pixels,
 7945        editor_snapshot: &EditorSnapshot,
 7946        visible_row_range: Range<DisplayRow>,
 7947        scroll_top: f32,
 7948        scroll_bottom: f32,
 7949        line_layouts: &[LineWithInvisibles],
 7950        line_height: Pixels,
 7951        scroll_pixel_position: gpui::Point<Pixels>,
 7952        newest_selection_head: Option<DisplayPoint>,
 7953        editor_width: Pixels,
 7954        style: &EditorStyle,
 7955        window: &mut Window,
 7956        cx: &mut App,
 7957    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7958        if self.mode().is_minimap() {
 7959            return None;
 7960        }
 7961        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7962
 7963        if self.edit_prediction_visible_in_cursor_popover(true) {
 7964            return None;
 7965        }
 7966
 7967        match &active_inline_completion.completion {
 7968            InlineCompletion::Move { target, .. } => {
 7969                let target_display_point = target.to_display_point(editor_snapshot);
 7970
 7971                if self.edit_prediction_requires_modifier() {
 7972                    if !self.edit_prediction_preview_is_active() {
 7973                        return None;
 7974                    }
 7975
 7976                    self.render_edit_prediction_modifier_jump_popover(
 7977                        text_bounds,
 7978                        content_origin,
 7979                        visible_row_range,
 7980                        line_layouts,
 7981                        line_height,
 7982                        scroll_pixel_position,
 7983                        newest_selection_head,
 7984                        target_display_point,
 7985                        window,
 7986                        cx,
 7987                    )
 7988                } else {
 7989                    self.render_edit_prediction_eager_jump_popover(
 7990                        text_bounds,
 7991                        content_origin,
 7992                        editor_snapshot,
 7993                        visible_row_range,
 7994                        scroll_top,
 7995                        scroll_bottom,
 7996                        line_height,
 7997                        scroll_pixel_position,
 7998                        target_display_point,
 7999                        editor_width,
 8000                        window,
 8001                        cx,
 8002                    )
 8003                }
 8004            }
 8005            InlineCompletion::Edit {
 8006                display_mode: EditDisplayMode::Inline,
 8007                ..
 8008            } => None,
 8009            InlineCompletion::Edit {
 8010                display_mode: EditDisplayMode::TabAccept,
 8011                edits,
 8012                ..
 8013            } => {
 8014                let range = &edits.first()?.0;
 8015                let target_display_point = range.end.to_display_point(editor_snapshot);
 8016
 8017                self.render_edit_prediction_end_of_line_popover(
 8018                    "Accept",
 8019                    editor_snapshot,
 8020                    visible_row_range,
 8021                    target_display_point,
 8022                    line_height,
 8023                    scroll_pixel_position,
 8024                    content_origin,
 8025                    editor_width,
 8026                    window,
 8027                    cx,
 8028                )
 8029            }
 8030            InlineCompletion::Edit {
 8031                edits,
 8032                edit_preview,
 8033                display_mode: EditDisplayMode::DiffPopover,
 8034                snapshot,
 8035            } => self.render_edit_prediction_diff_popover(
 8036                text_bounds,
 8037                content_origin,
 8038                right_margin,
 8039                editor_snapshot,
 8040                visible_row_range,
 8041                line_layouts,
 8042                line_height,
 8043                scroll_pixel_position,
 8044                newest_selection_head,
 8045                editor_width,
 8046                style,
 8047                edits,
 8048                edit_preview,
 8049                snapshot,
 8050                window,
 8051                cx,
 8052            ),
 8053        }
 8054    }
 8055
 8056    fn render_edit_prediction_modifier_jump_popover(
 8057        &mut self,
 8058        text_bounds: &Bounds<Pixels>,
 8059        content_origin: gpui::Point<Pixels>,
 8060        visible_row_range: Range<DisplayRow>,
 8061        line_layouts: &[LineWithInvisibles],
 8062        line_height: Pixels,
 8063        scroll_pixel_position: gpui::Point<Pixels>,
 8064        newest_selection_head: Option<DisplayPoint>,
 8065        target_display_point: DisplayPoint,
 8066        window: &mut Window,
 8067        cx: &mut App,
 8068    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8069        let scrolled_content_origin =
 8070            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8071
 8072        const SCROLL_PADDING_Y: Pixels = px(12.);
 8073
 8074        if target_display_point.row() < visible_row_range.start {
 8075            return self.render_edit_prediction_scroll_popover(
 8076                |_| SCROLL_PADDING_Y,
 8077                IconName::ArrowUp,
 8078                visible_row_range,
 8079                line_layouts,
 8080                newest_selection_head,
 8081                scrolled_content_origin,
 8082                window,
 8083                cx,
 8084            );
 8085        } else if target_display_point.row() >= visible_row_range.end {
 8086            return self.render_edit_prediction_scroll_popover(
 8087                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8088                IconName::ArrowDown,
 8089                visible_row_range,
 8090                line_layouts,
 8091                newest_selection_head,
 8092                scrolled_content_origin,
 8093                window,
 8094                cx,
 8095            );
 8096        }
 8097
 8098        const POLE_WIDTH: Pixels = px(2.);
 8099
 8100        let line_layout =
 8101            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8102        let target_column = target_display_point.column() as usize;
 8103
 8104        let target_x = line_layout.x_for_index(target_column);
 8105        let target_y =
 8106            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8107
 8108        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8109
 8110        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8111        border_color.l += 0.001;
 8112
 8113        let mut element = v_flex()
 8114            .items_end()
 8115            .when(flag_on_right, |el| el.items_start())
 8116            .child(if flag_on_right {
 8117                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8118                    .rounded_bl(px(0.))
 8119                    .rounded_tl(px(0.))
 8120                    .border_l_2()
 8121                    .border_color(border_color)
 8122            } else {
 8123                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8124                    .rounded_br(px(0.))
 8125                    .rounded_tr(px(0.))
 8126                    .border_r_2()
 8127                    .border_color(border_color)
 8128            })
 8129            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8130            .into_any();
 8131
 8132        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8133
 8134        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8135            - point(
 8136                if flag_on_right {
 8137                    POLE_WIDTH
 8138                } else {
 8139                    size.width - POLE_WIDTH
 8140                },
 8141                size.height - line_height,
 8142            );
 8143
 8144        origin.x = origin.x.max(content_origin.x);
 8145
 8146        element.prepaint_at(origin, window, cx);
 8147
 8148        Some((element, origin))
 8149    }
 8150
 8151    fn render_edit_prediction_scroll_popover(
 8152        &mut self,
 8153        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8154        scroll_icon: IconName,
 8155        visible_row_range: Range<DisplayRow>,
 8156        line_layouts: &[LineWithInvisibles],
 8157        newest_selection_head: Option<DisplayPoint>,
 8158        scrolled_content_origin: gpui::Point<Pixels>,
 8159        window: &mut Window,
 8160        cx: &mut App,
 8161    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8162        let mut element = self
 8163            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8164            .into_any();
 8165
 8166        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8167
 8168        let cursor = newest_selection_head?;
 8169        let cursor_row_layout =
 8170            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8171        let cursor_column = cursor.column() as usize;
 8172
 8173        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8174
 8175        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8176
 8177        element.prepaint_at(origin, window, cx);
 8178        Some((element, origin))
 8179    }
 8180
 8181    fn render_edit_prediction_eager_jump_popover(
 8182        &mut self,
 8183        text_bounds: &Bounds<Pixels>,
 8184        content_origin: gpui::Point<Pixels>,
 8185        editor_snapshot: &EditorSnapshot,
 8186        visible_row_range: Range<DisplayRow>,
 8187        scroll_top: f32,
 8188        scroll_bottom: f32,
 8189        line_height: Pixels,
 8190        scroll_pixel_position: gpui::Point<Pixels>,
 8191        target_display_point: DisplayPoint,
 8192        editor_width: Pixels,
 8193        window: &mut Window,
 8194        cx: &mut App,
 8195    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8196        if target_display_point.row().as_f32() < scroll_top {
 8197            let mut element = self
 8198                .render_edit_prediction_line_popover(
 8199                    "Jump to Edit",
 8200                    Some(IconName::ArrowUp),
 8201                    window,
 8202                    cx,
 8203                )?
 8204                .into_any();
 8205
 8206            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8207            let offset = point(
 8208                (text_bounds.size.width - size.width) / 2.,
 8209                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8210            );
 8211
 8212            let origin = text_bounds.origin + offset;
 8213            element.prepaint_at(origin, window, cx);
 8214            Some((element, origin))
 8215        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8216            let mut element = self
 8217                .render_edit_prediction_line_popover(
 8218                    "Jump to Edit",
 8219                    Some(IconName::ArrowDown),
 8220                    window,
 8221                    cx,
 8222                )?
 8223                .into_any();
 8224
 8225            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8226            let offset = point(
 8227                (text_bounds.size.width - size.width) / 2.,
 8228                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8229            );
 8230
 8231            let origin = text_bounds.origin + offset;
 8232            element.prepaint_at(origin, window, cx);
 8233            Some((element, origin))
 8234        } else {
 8235            self.render_edit_prediction_end_of_line_popover(
 8236                "Jump to Edit",
 8237                editor_snapshot,
 8238                visible_row_range,
 8239                target_display_point,
 8240                line_height,
 8241                scroll_pixel_position,
 8242                content_origin,
 8243                editor_width,
 8244                window,
 8245                cx,
 8246            )
 8247        }
 8248    }
 8249
 8250    fn render_edit_prediction_end_of_line_popover(
 8251        self: &mut Editor,
 8252        label: &'static str,
 8253        editor_snapshot: &EditorSnapshot,
 8254        visible_row_range: Range<DisplayRow>,
 8255        target_display_point: DisplayPoint,
 8256        line_height: Pixels,
 8257        scroll_pixel_position: gpui::Point<Pixels>,
 8258        content_origin: gpui::Point<Pixels>,
 8259        editor_width: Pixels,
 8260        window: &mut Window,
 8261        cx: &mut App,
 8262    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8263        let target_line_end = DisplayPoint::new(
 8264            target_display_point.row(),
 8265            editor_snapshot.line_len(target_display_point.row()),
 8266        );
 8267
 8268        let mut element = self
 8269            .render_edit_prediction_line_popover(label, None, window, cx)?
 8270            .into_any();
 8271
 8272        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8273
 8274        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8275
 8276        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8277        let mut origin = start_point
 8278            + line_origin
 8279            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8280        origin.x = origin.x.max(content_origin.x);
 8281
 8282        let max_x = content_origin.x + editor_width - size.width;
 8283
 8284        if origin.x > max_x {
 8285            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8286
 8287            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8288                origin.y += offset;
 8289                IconName::ArrowUp
 8290            } else {
 8291                origin.y -= offset;
 8292                IconName::ArrowDown
 8293            };
 8294
 8295            element = self
 8296                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8297                .into_any();
 8298
 8299            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8300
 8301            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8302        }
 8303
 8304        element.prepaint_at(origin, window, cx);
 8305        Some((element, origin))
 8306    }
 8307
 8308    fn render_edit_prediction_diff_popover(
 8309        self: &Editor,
 8310        text_bounds: &Bounds<Pixels>,
 8311        content_origin: gpui::Point<Pixels>,
 8312        right_margin: Pixels,
 8313        editor_snapshot: &EditorSnapshot,
 8314        visible_row_range: Range<DisplayRow>,
 8315        line_layouts: &[LineWithInvisibles],
 8316        line_height: Pixels,
 8317        scroll_pixel_position: gpui::Point<Pixels>,
 8318        newest_selection_head: Option<DisplayPoint>,
 8319        editor_width: Pixels,
 8320        style: &EditorStyle,
 8321        edits: &Vec<(Range<Anchor>, String)>,
 8322        edit_preview: &Option<language::EditPreview>,
 8323        snapshot: &language::BufferSnapshot,
 8324        window: &mut Window,
 8325        cx: &mut App,
 8326    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8327        let edit_start = edits
 8328            .first()
 8329            .unwrap()
 8330            .0
 8331            .start
 8332            .to_display_point(editor_snapshot);
 8333        let edit_end = edits
 8334            .last()
 8335            .unwrap()
 8336            .0
 8337            .end
 8338            .to_display_point(editor_snapshot);
 8339
 8340        let is_visible = visible_row_range.contains(&edit_start.row())
 8341            || visible_row_range.contains(&edit_end.row());
 8342        if !is_visible {
 8343            return None;
 8344        }
 8345
 8346        let highlighted_edits =
 8347            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8348
 8349        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8350        let line_count = highlighted_edits.text.lines().count();
 8351
 8352        const BORDER_WIDTH: Pixels = px(1.);
 8353
 8354        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8355        let has_keybind = keybind.is_some();
 8356
 8357        let mut element = h_flex()
 8358            .items_start()
 8359            .child(
 8360                h_flex()
 8361                    .bg(cx.theme().colors().editor_background)
 8362                    .border(BORDER_WIDTH)
 8363                    .shadow_sm()
 8364                    .border_color(cx.theme().colors().border)
 8365                    .rounded_l_lg()
 8366                    .when(line_count > 1, |el| el.rounded_br_lg())
 8367                    .pr_1()
 8368                    .child(styled_text),
 8369            )
 8370            .child(
 8371                h_flex()
 8372                    .h(line_height + BORDER_WIDTH * 2.)
 8373                    .px_1p5()
 8374                    .gap_1()
 8375                    // Workaround: For some reason, there's a gap if we don't do this
 8376                    .ml(-BORDER_WIDTH)
 8377                    .shadow(vec![gpui::BoxShadow {
 8378                        color: gpui::black().opacity(0.05),
 8379                        offset: point(px(1.), px(1.)),
 8380                        blur_radius: px(2.),
 8381                        spread_radius: px(0.),
 8382                    }])
 8383                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8384                    .border(BORDER_WIDTH)
 8385                    .border_color(cx.theme().colors().border)
 8386                    .rounded_r_lg()
 8387                    .id("edit_prediction_diff_popover_keybind")
 8388                    .when(!has_keybind, |el| {
 8389                        let status_colors = cx.theme().status();
 8390
 8391                        el.bg(status_colors.error_background)
 8392                            .border_color(status_colors.error.opacity(0.6))
 8393                            .child(Icon::new(IconName::Info).color(Color::Error))
 8394                            .cursor_default()
 8395                            .hoverable_tooltip(move |_window, cx| {
 8396                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8397                            })
 8398                    })
 8399                    .children(keybind),
 8400            )
 8401            .into_any();
 8402
 8403        let longest_row =
 8404            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8405        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8406            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8407        } else {
 8408            layout_line(
 8409                longest_row,
 8410                editor_snapshot,
 8411                style,
 8412                editor_width,
 8413                |_| false,
 8414                window,
 8415                cx,
 8416            )
 8417            .width
 8418        };
 8419
 8420        let viewport_bounds =
 8421            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8422                right: -right_margin,
 8423                ..Default::default()
 8424            });
 8425
 8426        let x_after_longest =
 8427            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8428                - scroll_pixel_position.x;
 8429
 8430        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8431
 8432        // Fully visible if it can be displayed within the window (allow overlapping other
 8433        // panes). However, this is only allowed if the popover starts within text_bounds.
 8434        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8435            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8436
 8437        let mut origin = if can_position_to_the_right {
 8438            point(
 8439                x_after_longest,
 8440                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8441                    - scroll_pixel_position.y,
 8442            )
 8443        } else {
 8444            let cursor_row = newest_selection_head.map(|head| head.row());
 8445            let above_edit = edit_start
 8446                .row()
 8447                .0
 8448                .checked_sub(line_count as u32)
 8449                .map(DisplayRow);
 8450            let below_edit = Some(edit_end.row() + 1);
 8451            let above_cursor =
 8452                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8453            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8454
 8455            // Place the edit popover adjacent to the edit if there is a location
 8456            // available that is onscreen and does not obscure the cursor. Otherwise,
 8457            // place it adjacent to the cursor.
 8458            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8459                .into_iter()
 8460                .flatten()
 8461                .find(|&start_row| {
 8462                    let end_row = start_row + line_count as u32;
 8463                    visible_row_range.contains(&start_row)
 8464                        && visible_row_range.contains(&end_row)
 8465                        && cursor_row.map_or(true, |cursor_row| {
 8466                            !((start_row..end_row).contains(&cursor_row))
 8467                        })
 8468                })?;
 8469
 8470            content_origin
 8471                + point(
 8472                    -scroll_pixel_position.x,
 8473                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8474                )
 8475        };
 8476
 8477        origin.x -= BORDER_WIDTH;
 8478
 8479        window.defer_draw(element, origin, 1);
 8480
 8481        // Do not return an element, since it will already be drawn due to defer_draw.
 8482        None
 8483    }
 8484
 8485    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8486        px(30.)
 8487    }
 8488
 8489    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8490        if self.read_only(cx) {
 8491            cx.theme().players().read_only()
 8492        } else {
 8493            self.style.as_ref().unwrap().local_player
 8494        }
 8495    }
 8496
 8497    fn render_edit_prediction_accept_keybind(
 8498        &self,
 8499        window: &mut Window,
 8500        cx: &App,
 8501    ) -> Option<AnyElement> {
 8502        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8503        let accept_keystroke = accept_binding.keystroke()?;
 8504
 8505        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8506
 8507        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8508            Color::Accent
 8509        } else {
 8510            Color::Muted
 8511        };
 8512
 8513        h_flex()
 8514            .px_0p5()
 8515            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8516            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8517            .text_size(TextSize::XSmall.rems(cx))
 8518            .child(h_flex().children(ui::render_modifiers(
 8519                &accept_keystroke.modifiers,
 8520                PlatformStyle::platform(),
 8521                Some(modifiers_color),
 8522                Some(IconSize::XSmall.rems().into()),
 8523                true,
 8524            )))
 8525            .when(is_platform_style_mac, |parent| {
 8526                parent.child(accept_keystroke.key.clone())
 8527            })
 8528            .when(!is_platform_style_mac, |parent| {
 8529                parent.child(
 8530                    Key::new(
 8531                        util::capitalize(&accept_keystroke.key),
 8532                        Some(Color::Default),
 8533                    )
 8534                    .size(Some(IconSize::XSmall.rems().into())),
 8535                )
 8536            })
 8537            .into_any()
 8538            .into()
 8539    }
 8540
 8541    fn render_edit_prediction_line_popover(
 8542        &self,
 8543        label: impl Into<SharedString>,
 8544        icon: Option<IconName>,
 8545        window: &mut Window,
 8546        cx: &App,
 8547    ) -> Option<Stateful<Div>> {
 8548        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8549
 8550        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8551        let has_keybind = keybind.is_some();
 8552
 8553        let result = h_flex()
 8554            .id("ep-line-popover")
 8555            .py_0p5()
 8556            .pl_1()
 8557            .pr(padding_right)
 8558            .gap_1()
 8559            .rounded_md()
 8560            .border_1()
 8561            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8562            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8563            .shadow_sm()
 8564            .when(!has_keybind, |el| {
 8565                let status_colors = cx.theme().status();
 8566
 8567                el.bg(status_colors.error_background)
 8568                    .border_color(status_colors.error.opacity(0.6))
 8569                    .pl_2()
 8570                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8571                    .cursor_default()
 8572                    .hoverable_tooltip(move |_window, cx| {
 8573                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8574                    })
 8575            })
 8576            .children(keybind)
 8577            .child(
 8578                Label::new(label)
 8579                    .size(LabelSize::Small)
 8580                    .when(!has_keybind, |el| {
 8581                        el.color(cx.theme().status().error.into()).strikethrough()
 8582                    }),
 8583            )
 8584            .when(!has_keybind, |el| {
 8585                el.child(
 8586                    h_flex().ml_1().child(
 8587                        Icon::new(IconName::Info)
 8588                            .size(IconSize::Small)
 8589                            .color(cx.theme().status().error.into()),
 8590                    ),
 8591                )
 8592            })
 8593            .when_some(icon, |element, icon| {
 8594                element.child(
 8595                    div()
 8596                        .mt(px(1.5))
 8597                        .child(Icon::new(icon).size(IconSize::Small)),
 8598                )
 8599            });
 8600
 8601        Some(result)
 8602    }
 8603
 8604    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8605        let accent_color = cx.theme().colors().text_accent;
 8606        let editor_bg_color = cx.theme().colors().editor_background;
 8607        editor_bg_color.blend(accent_color.opacity(0.1))
 8608    }
 8609
 8610    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8611        let accent_color = cx.theme().colors().text_accent;
 8612        let editor_bg_color = cx.theme().colors().editor_background;
 8613        editor_bg_color.blend(accent_color.opacity(0.6))
 8614    }
 8615
 8616    fn render_edit_prediction_cursor_popover(
 8617        &self,
 8618        min_width: Pixels,
 8619        max_width: Pixels,
 8620        cursor_point: Point,
 8621        style: &EditorStyle,
 8622        accept_keystroke: Option<&gpui::Keystroke>,
 8623        _window: &Window,
 8624        cx: &mut Context<Editor>,
 8625    ) -> Option<AnyElement> {
 8626        let provider = self.edit_prediction_provider.as_ref()?;
 8627
 8628        if provider.provider.needs_terms_acceptance(cx) {
 8629            return Some(
 8630                h_flex()
 8631                    .min_w(min_width)
 8632                    .flex_1()
 8633                    .px_2()
 8634                    .py_1()
 8635                    .gap_3()
 8636                    .elevation_2(cx)
 8637                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8638                    .id("accept-terms")
 8639                    .cursor_pointer()
 8640                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8641                    .on_click(cx.listener(|this, _event, window, cx| {
 8642                        cx.stop_propagation();
 8643                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8644                        window.dispatch_action(
 8645                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8646                            cx,
 8647                        );
 8648                    }))
 8649                    .child(
 8650                        h_flex()
 8651                            .flex_1()
 8652                            .gap_2()
 8653                            .child(Icon::new(IconName::ZedPredict))
 8654                            .child(Label::new("Accept Terms of Service"))
 8655                            .child(div().w_full())
 8656                            .child(
 8657                                Icon::new(IconName::ArrowUpRight)
 8658                                    .color(Color::Muted)
 8659                                    .size(IconSize::Small),
 8660                            )
 8661                            .into_any_element(),
 8662                    )
 8663                    .into_any(),
 8664            );
 8665        }
 8666
 8667        let is_refreshing = provider.provider.is_refreshing(cx);
 8668
 8669        fn pending_completion_container() -> Div {
 8670            h_flex()
 8671                .h_full()
 8672                .flex_1()
 8673                .gap_2()
 8674                .child(Icon::new(IconName::ZedPredict))
 8675        }
 8676
 8677        let completion = match &self.active_inline_completion {
 8678            Some(prediction) => {
 8679                if !self.has_visible_completions_menu() {
 8680                    const RADIUS: Pixels = px(6.);
 8681                    const BORDER_WIDTH: Pixels = px(1.);
 8682
 8683                    return Some(
 8684                        h_flex()
 8685                            .elevation_2(cx)
 8686                            .border(BORDER_WIDTH)
 8687                            .border_color(cx.theme().colors().border)
 8688                            .when(accept_keystroke.is_none(), |el| {
 8689                                el.border_color(cx.theme().status().error)
 8690                            })
 8691                            .rounded(RADIUS)
 8692                            .rounded_tl(px(0.))
 8693                            .overflow_hidden()
 8694                            .child(div().px_1p5().child(match &prediction.completion {
 8695                                InlineCompletion::Move { target, snapshot } => {
 8696                                    use text::ToPoint as _;
 8697                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8698                                    {
 8699                                        Icon::new(IconName::ZedPredictDown)
 8700                                    } else {
 8701                                        Icon::new(IconName::ZedPredictUp)
 8702                                    }
 8703                                }
 8704                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8705                            }))
 8706                            .child(
 8707                                h_flex()
 8708                                    .gap_1()
 8709                                    .py_1()
 8710                                    .px_2()
 8711                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8712                                    .border_l_1()
 8713                                    .border_color(cx.theme().colors().border)
 8714                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8715                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8716                                        el.child(
 8717                                            Label::new("Hold")
 8718                                                .size(LabelSize::Small)
 8719                                                .when(accept_keystroke.is_none(), |el| {
 8720                                                    el.strikethrough()
 8721                                                })
 8722                                                .line_height_style(LineHeightStyle::UiLabel),
 8723                                        )
 8724                                    })
 8725                                    .id("edit_prediction_cursor_popover_keybind")
 8726                                    .when(accept_keystroke.is_none(), |el| {
 8727                                        let status_colors = cx.theme().status();
 8728
 8729                                        el.bg(status_colors.error_background)
 8730                                            .border_color(status_colors.error.opacity(0.6))
 8731                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8732                                            .cursor_default()
 8733                                            .hoverable_tooltip(move |_window, cx| {
 8734                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8735                                                    .into()
 8736                                            })
 8737                                    })
 8738                                    .when_some(
 8739                                        accept_keystroke.as_ref(),
 8740                                        |el, accept_keystroke| {
 8741                                            el.child(h_flex().children(ui::render_modifiers(
 8742                                                &accept_keystroke.modifiers,
 8743                                                PlatformStyle::platform(),
 8744                                                Some(Color::Default),
 8745                                                Some(IconSize::XSmall.rems().into()),
 8746                                                false,
 8747                                            )))
 8748                                        },
 8749                                    ),
 8750                            )
 8751                            .into_any(),
 8752                    );
 8753                }
 8754
 8755                self.render_edit_prediction_cursor_popover_preview(
 8756                    prediction,
 8757                    cursor_point,
 8758                    style,
 8759                    cx,
 8760                )?
 8761            }
 8762
 8763            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8764                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8765                    stale_completion,
 8766                    cursor_point,
 8767                    style,
 8768                    cx,
 8769                )?,
 8770
 8771                None => {
 8772                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8773                }
 8774            },
 8775
 8776            None => pending_completion_container().child(Label::new("No Prediction")),
 8777        };
 8778
 8779        let completion = if is_refreshing {
 8780            completion
 8781                .with_animation(
 8782                    "loading-completion",
 8783                    Animation::new(Duration::from_secs(2))
 8784                        .repeat()
 8785                        .with_easing(pulsating_between(0.4, 0.8)),
 8786                    |label, delta| label.opacity(delta),
 8787                )
 8788                .into_any_element()
 8789        } else {
 8790            completion.into_any_element()
 8791        };
 8792
 8793        let has_completion = self.active_inline_completion.is_some();
 8794
 8795        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8796        Some(
 8797            h_flex()
 8798                .min_w(min_width)
 8799                .max_w(max_width)
 8800                .flex_1()
 8801                .elevation_2(cx)
 8802                .border_color(cx.theme().colors().border)
 8803                .child(
 8804                    div()
 8805                        .flex_1()
 8806                        .py_1()
 8807                        .px_2()
 8808                        .overflow_hidden()
 8809                        .child(completion),
 8810                )
 8811                .when_some(accept_keystroke, |el, accept_keystroke| {
 8812                    if !accept_keystroke.modifiers.modified() {
 8813                        return el;
 8814                    }
 8815
 8816                    el.child(
 8817                        h_flex()
 8818                            .h_full()
 8819                            .border_l_1()
 8820                            .rounded_r_lg()
 8821                            .border_color(cx.theme().colors().border)
 8822                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8823                            .gap_1()
 8824                            .py_1()
 8825                            .px_2()
 8826                            .child(
 8827                                h_flex()
 8828                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8829                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8830                                    .child(h_flex().children(ui::render_modifiers(
 8831                                        &accept_keystroke.modifiers,
 8832                                        PlatformStyle::platform(),
 8833                                        Some(if !has_completion {
 8834                                            Color::Muted
 8835                                        } else {
 8836                                            Color::Default
 8837                                        }),
 8838                                        None,
 8839                                        false,
 8840                                    ))),
 8841                            )
 8842                            .child(Label::new("Preview").into_any_element())
 8843                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8844                    )
 8845                })
 8846                .into_any(),
 8847        )
 8848    }
 8849
 8850    fn render_edit_prediction_cursor_popover_preview(
 8851        &self,
 8852        completion: &InlineCompletionState,
 8853        cursor_point: Point,
 8854        style: &EditorStyle,
 8855        cx: &mut Context<Editor>,
 8856    ) -> Option<Div> {
 8857        use text::ToPoint as _;
 8858
 8859        fn render_relative_row_jump(
 8860            prefix: impl Into<String>,
 8861            current_row: u32,
 8862            target_row: u32,
 8863        ) -> Div {
 8864            let (row_diff, arrow) = if target_row < current_row {
 8865                (current_row - target_row, IconName::ArrowUp)
 8866            } else {
 8867                (target_row - current_row, IconName::ArrowDown)
 8868            };
 8869
 8870            h_flex()
 8871                .child(
 8872                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8873                        .color(Color::Muted)
 8874                        .size(LabelSize::Small),
 8875                )
 8876                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8877        }
 8878
 8879        match &completion.completion {
 8880            InlineCompletion::Move {
 8881                target, snapshot, ..
 8882            } => Some(
 8883                h_flex()
 8884                    .px_2()
 8885                    .gap_2()
 8886                    .flex_1()
 8887                    .child(
 8888                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8889                            Icon::new(IconName::ZedPredictDown)
 8890                        } else {
 8891                            Icon::new(IconName::ZedPredictUp)
 8892                        },
 8893                    )
 8894                    .child(Label::new("Jump to Edit")),
 8895            ),
 8896
 8897            InlineCompletion::Edit {
 8898                edits,
 8899                edit_preview,
 8900                snapshot,
 8901                display_mode: _,
 8902            } => {
 8903                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8904
 8905                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8906                    &snapshot,
 8907                    &edits,
 8908                    edit_preview.as_ref()?,
 8909                    true,
 8910                    cx,
 8911                )
 8912                .first_line_preview();
 8913
 8914                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8915                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8916
 8917                let preview = h_flex()
 8918                    .gap_1()
 8919                    .min_w_16()
 8920                    .child(styled_text)
 8921                    .when(has_more_lines, |parent| parent.child(""));
 8922
 8923                let left = if first_edit_row != cursor_point.row {
 8924                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8925                        .into_any_element()
 8926                } else {
 8927                    Icon::new(IconName::ZedPredict).into_any_element()
 8928                };
 8929
 8930                Some(
 8931                    h_flex()
 8932                        .h_full()
 8933                        .flex_1()
 8934                        .gap_2()
 8935                        .pr_1()
 8936                        .overflow_x_hidden()
 8937                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8938                        .child(left)
 8939                        .child(preview),
 8940                )
 8941            }
 8942        }
 8943    }
 8944
 8945    pub fn render_context_menu(
 8946        &self,
 8947        style: &EditorStyle,
 8948        max_height_in_lines: u32,
 8949        window: &mut Window,
 8950        cx: &mut Context<Editor>,
 8951    ) -> Option<AnyElement> {
 8952        let menu = self.context_menu.borrow();
 8953        let menu = menu.as_ref()?;
 8954        if !menu.visible() {
 8955            return None;
 8956        };
 8957        Some(menu.render(style, max_height_in_lines, window, cx))
 8958    }
 8959
 8960    fn render_context_menu_aside(
 8961        &mut self,
 8962        max_size: Size<Pixels>,
 8963        window: &mut Window,
 8964        cx: &mut Context<Editor>,
 8965    ) -> Option<AnyElement> {
 8966        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8967            if menu.visible() {
 8968                menu.render_aside(max_size, window, cx)
 8969            } else {
 8970                None
 8971            }
 8972        })
 8973    }
 8974
 8975    fn hide_context_menu(
 8976        &mut self,
 8977        window: &mut Window,
 8978        cx: &mut Context<Self>,
 8979    ) -> Option<CodeContextMenu> {
 8980        cx.notify();
 8981        self.completion_tasks.clear();
 8982        let context_menu = self.context_menu.borrow_mut().take();
 8983        self.stale_inline_completion_in_menu.take();
 8984        self.update_visible_inline_completion(window, cx);
 8985        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8986            if let Some(completion_provider) = &self.completion_provider {
 8987                completion_provider.selection_changed(None, window, cx);
 8988            }
 8989        }
 8990        context_menu
 8991    }
 8992
 8993    fn show_snippet_choices(
 8994        &mut self,
 8995        choices: &Vec<String>,
 8996        selection: Range<Anchor>,
 8997        cx: &mut Context<Self>,
 8998    ) {
 8999        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9000            (Some(a), Some(b)) if a == b => a,
 9001            _ => {
 9002                log::error!("expected anchor range to have matching buffer IDs");
 9003                return;
 9004            }
 9005        };
 9006        let multi_buffer = self.buffer().read(cx);
 9007        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9008            return;
 9009        };
 9010
 9011        let id = post_inc(&mut self.next_completion_id);
 9012        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9013        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9014            CompletionsMenu::new_snippet_choices(
 9015                id,
 9016                true,
 9017                choices,
 9018                selection,
 9019                buffer,
 9020                snippet_sort_order,
 9021            ),
 9022        ));
 9023    }
 9024
 9025    pub fn insert_snippet(
 9026        &mut self,
 9027        insertion_ranges: &[Range<usize>],
 9028        snippet: Snippet,
 9029        window: &mut Window,
 9030        cx: &mut Context<Self>,
 9031    ) -> Result<()> {
 9032        struct Tabstop<T> {
 9033            is_end_tabstop: bool,
 9034            ranges: Vec<Range<T>>,
 9035            choices: Option<Vec<String>>,
 9036        }
 9037
 9038        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9039            let snippet_text: Arc<str> = snippet.text.clone().into();
 9040            let edits = insertion_ranges
 9041                .iter()
 9042                .cloned()
 9043                .map(|range| (range, snippet_text.clone()));
 9044            let autoindent_mode = AutoindentMode::Block {
 9045                original_indent_columns: Vec::new(),
 9046            };
 9047            buffer.edit(edits, Some(autoindent_mode), cx);
 9048
 9049            let snapshot = &*buffer.read(cx);
 9050            let snippet = &snippet;
 9051            snippet
 9052                .tabstops
 9053                .iter()
 9054                .map(|tabstop| {
 9055                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9056                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9057                    });
 9058                    let mut tabstop_ranges = tabstop
 9059                        .ranges
 9060                        .iter()
 9061                        .flat_map(|tabstop_range| {
 9062                            let mut delta = 0_isize;
 9063                            insertion_ranges.iter().map(move |insertion_range| {
 9064                                let insertion_start = insertion_range.start as isize + delta;
 9065                                delta +=
 9066                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9067
 9068                                let start = ((insertion_start + tabstop_range.start) as usize)
 9069                                    .min(snapshot.len());
 9070                                let end = ((insertion_start + tabstop_range.end) as usize)
 9071                                    .min(snapshot.len());
 9072                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9073                            })
 9074                        })
 9075                        .collect::<Vec<_>>();
 9076                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9077
 9078                    Tabstop {
 9079                        is_end_tabstop,
 9080                        ranges: tabstop_ranges,
 9081                        choices: tabstop.choices.clone(),
 9082                    }
 9083                })
 9084                .collect::<Vec<_>>()
 9085        });
 9086        if let Some(tabstop) = tabstops.first() {
 9087            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9088                // Reverse order so that the first range is the newest created selection.
 9089                // Completions will use it and autoscroll will prioritize it.
 9090                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9091            });
 9092
 9093            if let Some(choices) = &tabstop.choices {
 9094                if let Some(selection) = tabstop.ranges.first() {
 9095                    self.show_snippet_choices(choices, selection.clone(), cx)
 9096                }
 9097            }
 9098
 9099            // If we're already at the last tabstop and it's at the end of the snippet,
 9100            // we're done, we don't need to keep the state around.
 9101            if !tabstop.is_end_tabstop {
 9102                let choices = tabstops
 9103                    .iter()
 9104                    .map(|tabstop| tabstop.choices.clone())
 9105                    .collect();
 9106
 9107                let ranges = tabstops
 9108                    .into_iter()
 9109                    .map(|tabstop| tabstop.ranges)
 9110                    .collect::<Vec<_>>();
 9111
 9112                self.snippet_stack.push(SnippetState {
 9113                    active_index: 0,
 9114                    ranges,
 9115                    choices,
 9116                });
 9117            }
 9118
 9119            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9120            if self.autoclose_regions.is_empty() {
 9121                let snapshot = self.buffer.read(cx).snapshot(cx);
 9122                for selection in &mut self.selections.all::<Point>(cx) {
 9123                    let selection_head = selection.head();
 9124                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9125                        continue;
 9126                    };
 9127
 9128                    let mut bracket_pair = None;
 9129                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9130                    let prev_chars = snapshot
 9131                        .reversed_chars_at(selection_head)
 9132                        .collect::<String>();
 9133                    for (pair, enabled) in scope.brackets() {
 9134                        if enabled
 9135                            && pair.close
 9136                            && prev_chars.starts_with(pair.start.as_str())
 9137                            && next_chars.starts_with(pair.end.as_str())
 9138                        {
 9139                            bracket_pair = Some(pair.clone());
 9140                            break;
 9141                        }
 9142                    }
 9143                    if let Some(pair) = bracket_pair {
 9144                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9145                        let autoclose_enabled =
 9146                            self.use_autoclose && snapshot_settings.use_autoclose;
 9147                        if autoclose_enabled {
 9148                            let start = snapshot.anchor_after(selection_head);
 9149                            let end = snapshot.anchor_after(selection_head);
 9150                            self.autoclose_regions.push(AutocloseRegion {
 9151                                selection_id: selection.id,
 9152                                range: start..end,
 9153                                pair,
 9154                            });
 9155                        }
 9156                    }
 9157                }
 9158            }
 9159        }
 9160        Ok(())
 9161    }
 9162
 9163    pub fn move_to_next_snippet_tabstop(
 9164        &mut self,
 9165        window: &mut Window,
 9166        cx: &mut Context<Self>,
 9167    ) -> bool {
 9168        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9169    }
 9170
 9171    pub fn move_to_prev_snippet_tabstop(
 9172        &mut self,
 9173        window: &mut Window,
 9174        cx: &mut Context<Self>,
 9175    ) -> bool {
 9176        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9177    }
 9178
 9179    pub fn move_to_snippet_tabstop(
 9180        &mut self,
 9181        bias: Bias,
 9182        window: &mut Window,
 9183        cx: &mut Context<Self>,
 9184    ) -> bool {
 9185        if let Some(mut snippet) = self.snippet_stack.pop() {
 9186            match bias {
 9187                Bias::Left => {
 9188                    if snippet.active_index > 0 {
 9189                        snippet.active_index -= 1;
 9190                    } else {
 9191                        self.snippet_stack.push(snippet);
 9192                        return false;
 9193                    }
 9194                }
 9195                Bias::Right => {
 9196                    if snippet.active_index + 1 < snippet.ranges.len() {
 9197                        snippet.active_index += 1;
 9198                    } else {
 9199                        self.snippet_stack.push(snippet);
 9200                        return false;
 9201                    }
 9202                }
 9203            }
 9204            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9205                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9206                    // Reverse order so that the first range is the newest created selection.
 9207                    // Completions will use it and autoscroll will prioritize it.
 9208                    s.select_ranges(current_ranges.iter().rev().cloned())
 9209                });
 9210
 9211                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9212                    if let Some(selection) = current_ranges.first() {
 9213                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9214                    }
 9215                }
 9216
 9217                // If snippet state is not at the last tabstop, push it back on the stack
 9218                if snippet.active_index + 1 < snippet.ranges.len() {
 9219                    self.snippet_stack.push(snippet);
 9220                }
 9221                return true;
 9222            }
 9223        }
 9224
 9225        false
 9226    }
 9227
 9228    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9229        self.transact(window, cx, |this, window, cx| {
 9230            this.select_all(&SelectAll, window, cx);
 9231            this.insert("", window, cx);
 9232        });
 9233    }
 9234
 9235    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9236        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9237        self.transact(window, cx, |this, window, cx| {
 9238            this.select_autoclose_pair(window, cx);
 9239            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9240            if !this.linked_edit_ranges.is_empty() {
 9241                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9242                let snapshot = this.buffer.read(cx).snapshot(cx);
 9243
 9244                for selection in selections.iter() {
 9245                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9246                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9247                    if selection_start.buffer_id != selection_end.buffer_id {
 9248                        continue;
 9249                    }
 9250                    if let Some(ranges) =
 9251                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9252                    {
 9253                        for (buffer, entries) in ranges {
 9254                            linked_ranges.entry(buffer).or_default().extend(entries);
 9255                        }
 9256                    }
 9257                }
 9258            }
 9259
 9260            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9261            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9262            for selection in &mut selections {
 9263                if selection.is_empty() {
 9264                    let old_head = selection.head();
 9265                    let mut new_head =
 9266                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9267                            .to_point(&display_map);
 9268                    if let Some((buffer, line_buffer_range)) = display_map
 9269                        .buffer_snapshot
 9270                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9271                    {
 9272                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9273                        let indent_len = match indent_size.kind {
 9274                            IndentKind::Space => {
 9275                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9276                            }
 9277                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9278                        };
 9279                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9280                            let indent_len = indent_len.get();
 9281                            new_head = cmp::min(
 9282                                new_head,
 9283                                MultiBufferPoint::new(
 9284                                    old_head.row,
 9285                                    ((old_head.column - 1) / indent_len) * indent_len,
 9286                                ),
 9287                            );
 9288                        }
 9289                    }
 9290
 9291                    selection.set_head(new_head, SelectionGoal::None);
 9292                }
 9293            }
 9294
 9295            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9296                s.select(selections)
 9297            });
 9298            this.insert("", window, cx);
 9299            let empty_str: Arc<str> = Arc::from("");
 9300            for (buffer, edits) in linked_ranges {
 9301                let snapshot = buffer.read(cx).snapshot();
 9302                use text::ToPoint as TP;
 9303
 9304                let edits = edits
 9305                    .into_iter()
 9306                    .map(|range| {
 9307                        let end_point = TP::to_point(&range.end, &snapshot);
 9308                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9309
 9310                        if end_point == start_point {
 9311                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9312                                .saturating_sub(1);
 9313                            start_point =
 9314                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9315                        };
 9316
 9317                        (start_point..end_point, empty_str.clone())
 9318                    })
 9319                    .sorted_by_key(|(range, _)| range.start)
 9320                    .collect::<Vec<_>>();
 9321                buffer.update(cx, |this, cx| {
 9322                    this.edit(edits, None, cx);
 9323                })
 9324            }
 9325            this.refresh_inline_completion(true, false, window, cx);
 9326            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9327        });
 9328    }
 9329
 9330    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9331        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9332        self.transact(window, cx, |this, window, cx| {
 9333            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9334                s.move_with(|map, selection| {
 9335                    if selection.is_empty() {
 9336                        let cursor = movement::right(map, selection.head());
 9337                        selection.end = cursor;
 9338                        selection.reversed = true;
 9339                        selection.goal = SelectionGoal::None;
 9340                    }
 9341                })
 9342            });
 9343            this.insert("", window, cx);
 9344            this.refresh_inline_completion(true, false, window, cx);
 9345        });
 9346    }
 9347
 9348    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9350        if self.move_to_prev_snippet_tabstop(window, cx) {
 9351            return;
 9352        }
 9353        self.outdent(&Outdent, window, cx);
 9354    }
 9355
 9356    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9357        if self.move_to_next_snippet_tabstop(window, cx) {
 9358            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9359            return;
 9360        }
 9361        if self.read_only(cx) {
 9362            return;
 9363        }
 9364        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9365        let mut selections = self.selections.all_adjusted(cx);
 9366        let buffer = self.buffer.read(cx);
 9367        let snapshot = buffer.snapshot(cx);
 9368        let rows_iter = selections.iter().map(|s| s.head().row);
 9369        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9370
 9371        let has_some_cursor_in_whitespace = selections
 9372            .iter()
 9373            .filter(|selection| selection.is_empty())
 9374            .any(|selection| {
 9375                let cursor = selection.head();
 9376                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9377                cursor.column < current_indent.len
 9378            });
 9379
 9380        let mut edits = Vec::new();
 9381        let mut prev_edited_row = 0;
 9382        let mut row_delta = 0;
 9383        for selection in &mut selections {
 9384            if selection.start.row != prev_edited_row {
 9385                row_delta = 0;
 9386            }
 9387            prev_edited_row = selection.end.row;
 9388
 9389            // If the selection is non-empty, then increase the indentation of the selected lines.
 9390            if !selection.is_empty() {
 9391                row_delta =
 9392                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9393                continue;
 9394            }
 9395
 9396            let cursor = selection.head();
 9397            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9398            if let Some(suggested_indent) =
 9399                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9400            {
 9401                // Don't do anything if already at suggested indent
 9402                // and there is any other cursor which is not
 9403                if has_some_cursor_in_whitespace
 9404                    && cursor.column == current_indent.len
 9405                    && current_indent.len == suggested_indent.len
 9406                {
 9407                    continue;
 9408                }
 9409
 9410                // Adjust line and move cursor to suggested indent
 9411                // if cursor is not at suggested indent
 9412                if cursor.column < suggested_indent.len
 9413                    && cursor.column <= current_indent.len
 9414                    && current_indent.len <= suggested_indent.len
 9415                {
 9416                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9417                    selection.end = selection.start;
 9418                    if row_delta == 0 {
 9419                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9420                            cursor.row,
 9421                            current_indent,
 9422                            suggested_indent,
 9423                        ));
 9424                        row_delta = suggested_indent.len - current_indent.len;
 9425                    }
 9426                    continue;
 9427                }
 9428
 9429                // If current indent is more than suggested indent
 9430                // only move cursor to current indent and skip indent
 9431                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9432                    selection.start = Point::new(cursor.row, current_indent.len);
 9433                    selection.end = selection.start;
 9434                    continue;
 9435                }
 9436            }
 9437
 9438            // Otherwise, insert a hard or soft tab.
 9439            let settings = buffer.language_settings_at(cursor, cx);
 9440            let tab_size = if settings.hard_tabs {
 9441                IndentSize::tab()
 9442            } else {
 9443                let tab_size = settings.tab_size.get();
 9444                let indent_remainder = snapshot
 9445                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9446                    .flat_map(str::chars)
 9447                    .fold(row_delta % tab_size, |counter: u32, c| {
 9448                        if c == '\t' {
 9449                            0
 9450                        } else {
 9451                            (counter + 1) % tab_size
 9452                        }
 9453                    });
 9454
 9455                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9456                IndentSize::spaces(chars_to_next_tab_stop)
 9457            };
 9458            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9459            selection.end = selection.start;
 9460            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9461            row_delta += tab_size.len;
 9462        }
 9463
 9464        self.transact(window, cx, |this, window, cx| {
 9465            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9466            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9467                s.select(selections)
 9468            });
 9469            this.refresh_inline_completion(true, false, window, cx);
 9470        });
 9471    }
 9472
 9473    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9474        if self.read_only(cx) {
 9475            return;
 9476        }
 9477        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9478        let mut selections = self.selections.all::<Point>(cx);
 9479        let mut prev_edited_row = 0;
 9480        let mut row_delta = 0;
 9481        let mut edits = Vec::new();
 9482        let buffer = self.buffer.read(cx);
 9483        let snapshot = buffer.snapshot(cx);
 9484        for selection in &mut selections {
 9485            if selection.start.row != prev_edited_row {
 9486                row_delta = 0;
 9487            }
 9488            prev_edited_row = selection.end.row;
 9489
 9490            row_delta =
 9491                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9492        }
 9493
 9494        self.transact(window, cx, |this, window, cx| {
 9495            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9496            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9497                s.select(selections)
 9498            });
 9499        });
 9500    }
 9501
 9502    fn indent_selection(
 9503        buffer: &MultiBuffer,
 9504        snapshot: &MultiBufferSnapshot,
 9505        selection: &mut Selection<Point>,
 9506        edits: &mut Vec<(Range<Point>, String)>,
 9507        delta_for_start_row: u32,
 9508        cx: &App,
 9509    ) -> u32 {
 9510        let settings = buffer.language_settings_at(selection.start, cx);
 9511        let tab_size = settings.tab_size.get();
 9512        let indent_kind = if settings.hard_tabs {
 9513            IndentKind::Tab
 9514        } else {
 9515            IndentKind::Space
 9516        };
 9517        let mut start_row = selection.start.row;
 9518        let mut end_row = selection.end.row + 1;
 9519
 9520        // If a selection ends at the beginning of a line, don't indent
 9521        // that last line.
 9522        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9523            end_row -= 1;
 9524        }
 9525
 9526        // Avoid re-indenting a row that has already been indented by a
 9527        // previous selection, but still update this selection's column
 9528        // to reflect that indentation.
 9529        if delta_for_start_row > 0 {
 9530            start_row += 1;
 9531            selection.start.column += delta_for_start_row;
 9532            if selection.end.row == selection.start.row {
 9533                selection.end.column += delta_for_start_row;
 9534            }
 9535        }
 9536
 9537        let mut delta_for_end_row = 0;
 9538        let has_multiple_rows = start_row + 1 != end_row;
 9539        for row in start_row..end_row {
 9540            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9541            let indent_delta = match (current_indent.kind, indent_kind) {
 9542                (IndentKind::Space, IndentKind::Space) => {
 9543                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9544                    IndentSize::spaces(columns_to_next_tab_stop)
 9545                }
 9546                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9547                (_, IndentKind::Tab) => IndentSize::tab(),
 9548            };
 9549
 9550            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9551                0
 9552            } else {
 9553                selection.start.column
 9554            };
 9555            let row_start = Point::new(row, start);
 9556            edits.push((
 9557                row_start..row_start,
 9558                indent_delta.chars().collect::<String>(),
 9559            ));
 9560
 9561            // Update this selection's endpoints to reflect the indentation.
 9562            if row == selection.start.row {
 9563                selection.start.column += indent_delta.len;
 9564            }
 9565            if row == selection.end.row {
 9566                selection.end.column += indent_delta.len;
 9567                delta_for_end_row = indent_delta.len;
 9568            }
 9569        }
 9570
 9571        if selection.start.row == selection.end.row {
 9572            delta_for_start_row + delta_for_end_row
 9573        } else {
 9574            delta_for_end_row
 9575        }
 9576    }
 9577
 9578    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9579        if self.read_only(cx) {
 9580            return;
 9581        }
 9582        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9583        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9584        let selections = self.selections.all::<Point>(cx);
 9585        let mut deletion_ranges = Vec::new();
 9586        let mut last_outdent = None;
 9587        {
 9588            let buffer = self.buffer.read(cx);
 9589            let snapshot = buffer.snapshot(cx);
 9590            for selection in &selections {
 9591                let settings = buffer.language_settings_at(selection.start, cx);
 9592                let tab_size = settings.tab_size.get();
 9593                let mut rows = selection.spanned_rows(false, &display_map);
 9594
 9595                // Avoid re-outdenting a row that has already been outdented by a
 9596                // previous selection.
 9597                if let Some(last_row) = last_outdent {
 9598                    if last_row == rows.start {
 9599                        rows.start = rows.start.next_row();
 9600                    }
 9601                }
 9602                let has_multiple_rows = rows.len() > 1;
 9603                for row in rows.iter_rows() {
 9604                    let indent_size = snapshot.indent_size_for_line(row);
 9605                    if indent_size.len > 0 {
 9606                        let deletion_len = match indent_size.kind {
 9607                            IndentKind::Space => {
 9608                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9609                                if columns_to_prev_tab_stop == 0 {
 9610                                    tab_size
 9611                                } else {
 9612                                    columns_to_prev_tab_stop
 9613                                }
 9614                            }
 9615                            IndentKind::Tab => 1,
 9616                        };
 9617                        let start = if has_multiple_rows
 9618                            || deletion_len > selection.start.column
 9619                            || indent_size.len < selection.start.column
 9620                        {
 9621                            0
 9622                        } else {
 9623                            selection.start.column - deletion_len
 9624                        };
 9625                        deletion_ranges.push(
 9626                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9627                        );
 9628                        last_outdent = Some(row);
 9629                    }
 9630                }
 9631            }
 9632        }
 9633
 9634        self.transact(window, cx, |this, window, cx| {
 9635            this.buffer.update(cx, |buffer, cx| {
 9636                let empty_str: Arc<str> = Arc::default();
 9637                buffer.edit(
 9638                    deletion_ranges
 9639                        .into_iter()
 9640                        .map(|range| (range, empty_str.clone())),
 9641                    None,
 9642                    cx,
 9643                );
 9644            });
 9645            let selections = this.selections.all::<usize>(cx);
 9646            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9647                s.select(selections)
 9648            });
 9649        });
 9650    }
 9651
 9652    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9653        if self.read_only(cx) {
 9654            return;
 9655        }
 9656        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9657        let selections = self
 9658            .selections
 9659            .all::<usize>(cx)
 9660            .into_iter()
 9661            .map(|s| s.range());
 9662
 9663        self.transact(window, cx, |this, window, cx| {
 9664            this.buffer.update(cx, |buffer, cx| {
 9665                buffer.autoindent_ranges(selections, cx);
 9666            });
 9667            let selections = this.selections.all::<usize>(cx);
 9668            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9669                s.select(selections)
 9670            });
 9671        });
 9672    }
 9673
 9674    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9675        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9676        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9677        let selections = self.selections.all::<Point>(cx);
 9678
 9679        let mut new_cursors = Vec::new();
 9680        let mut edit_ranges = Vec::new();
 9681        let mut selections = selections.iter().peekable();
 9682        while let Some(selection) = selections.next() {
 9683            let mut rows = selection.spanned_rows(false, &display_map);
 9684            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9685
 9686            // Accumulate contiguous regions of rows that we want to delete.
 9687            while let Some(next_selection) = selections.peek() {
 9688                let next_rows = next_selection.spanned_rows(false, &display_map);
 9689                if next_rows.start <= rows.end {
 9690                    rows.end = next_rows.end;
 9691                    selections.next().unwrap();
 9692                } else {
 9693                    break;
 9694                }
 9695            }
 9696
 9697            let buffer = &display_map.buffer_snapshot;
 9698            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9699            let edit_end;
 9700            let cursor_buffer_row;
 9701            if buffer.max_point().row >= rows.end.0 {
 9702                // If there's a line after the range, delete the \n from the end of the row range
 9703                // and position the cursor on the next line.
 9704                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9705                cursor_buffer_row = rows.end;
 9706            } else {
 9707                // If there isn't a line after the range, delete the \n from the line before the
 9708                // start of the row range and position the cursor there.
 9709                edit_start = edit_start.saturating_sub(1);
 9710                edit_end = buffer.len();
 9711                cursor_buffer_row = rows.start.previous_row();
 9712            }
 9713
 9714            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9715            *cursor.column_mut() =
 9716                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9717
 9718            new_cursors.push((
 9719                selection.id,
 9720                buffer.anchor_after(cursor.to_point(&display_map)),
 9721            ));
 9722            edit_ranges.push(edit_start..edit_end);
 9723        }
 9724
 9725        self.transact(window, cx, |this, window, cx| {
 9726            let buffer = this.buffer.update(cx, |buffer, cx| {
 9727                let empty_str: Arc<str> = Arc::default();
 9728                buffer.edit(
 9729                    edit_ranges
 9730                        .into_iter()
 9731                        .map(|range| (range, empty_str.clone())),
 9732                    None,
 9733                    cx,
 9734                );
 9735                buffer.snapshot(cx)
 9736            });
 9737            let new_selections = new_cursors
 9738                .into_iter()
 9739                .map(|(id, cursor)| {
 9740                    let cursor = cursor.to_point(&buffer);
 9741                    Selection {
 9742                        id,
 9743                        start: cursor,
 9744                        end: cursor,
 9745                        reversed: false,
 9746                        goal: SelectionGoal::None,
 9747                    }
 9748                })
 9749                .collect();
 9750
 9751            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9752                s.select(new_selections);
 9753            });
 9754        });
 9755    }
 9756
 9757    pub fn join_lines_impl(
 9758        &mut self,
 9759        insert_whitespace: bool,
 9760        window: &mut Window,
 9761        cx: &mut Context<Self>,
 9762    ) {
 9763        if self.read_only(cx) {
 9764            return;
 9765        }
 9766        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9767        for selection in self.selections.all::<Point>(cx) {
 9768            let start = MultiBufferRow(selection.start.row);
 9769            // Treat single line selections as if they include the next line. Otherwise this action
 9770            // would do nothing for single line selections individual cursors.
 9771            let end = if selection.start.row == selection.end.row {
 9772                MultiBufferRow(selection.start.row + 1)
 9773            } else {
 9774                MultiBufferRow(selection.end.row)
 9775            };
 9776
 9777            if let Some(last_row_range) = row_ranges.last_mut() {
 9778                if start <= last_row_range.end {
 9779                    last_row_range.end = end;
 9780                    continue;
 9781                }
 9782            }
 9783            row_ranges.push(start..end);
 9784        }
 9785
 9786        let snapshot = self.buffer.read(cx).snapshot(cx);
 9787        let mut cursor_positions = Vec::new();
 9788        for row_range in &row_ranges {
 9789            let anchor = snapshot.anchor_before(Point::new(
 9790                row_range.end.previous_row().0,
 9791                snapshot.line_len(row_range.end.previous_row()),
 9792            ));
 9793            cursor_positions.push(anchor..anchor);
 9794        }
 9795
 9796        self.transact(window, cx, |this, window, cx| {
 9797            for row_range in row_ranges.into_iter().rev() {
 9798                for row in row_range.iter_rows().rev() {
 9799                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9800                    let next_line_row = row.next_row();
 9801                    let indent = snapshot.indent_size_for_line(next_line_row);
 9802                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9803
 9804                    let replace =
 9805                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9806                            " "
 9807                        } else {
 9808                            ""
 9809                        };
 9810
 9811                    this.buffer.update(cx, |buffer, cx| {
 9812                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9813                    });
 9814                }
 9815            }
 9816
 9817            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9818                s.select_anchor_ranges(cursor_positions)
 9819            });
 9820        });
 9821    }
 9822
 9823    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9824        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9825        self.join_lines_impl(true, window, cx);
 9826    }
 9827
 9828    pub fn sort_lines_case_sensitive(
 9829        &mut self,
 9830        _: &SortLinesCaseSensitive,
 9831        window: &mut Window,
 9832        cx: &mut Context<Self>,
 9833    ) {
 9834        self.manipulate_lines(window, cx, |lines| lines.sort())
 9835    }
 9836
 9837    pub fn sort_lines_case_insensitive(
 9838        &mut self,
 9839        _: &SortLinesCaseInsensitive,
 9840        window: &mut Window,
 9841        cx: &mut Context<Self>,
 9842    ) {
 9843        self.manipulate_lines(window, cx, |lines| {
 9844            lines.sort_by_key(|line| line.to_lowercase())
 9845        })
 9846    }
 9847
 9848    pub fn unique_lines_case_insensitive(
 9849        &mut self,
 9850        _: &UniqueLinesCaseInsensitive,
 9851        window: &mut Window,
 9852        cx: &mut Context<Self>,
 9853    ) {
 9854        self.manipulate_lines(window, cx, |lines| {
 9855            let mut seen = HashSet::default();
 9856            lines.retain(|line| seen.insert(line.to_lowercase()));
 9857        })
 9858    }
 9859
 9860    pub fn unique_lines_case_sensitive(
 9861        &mut self,
 9862        _: &UniqueLinesCaseSensitive,
 9863        window: &mut Window,
 9864        cx: &mut Context<Self>,
 9865    ) {
 9866        self.manipulate_lines(window, cx, |lines| {
 9867            let mut seen = HashSet::default();
 9868            lines.retain(|line| seen.insert(*line));
 9869        })
 9870    }
 9871
 9872    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9873        let Some(project) = self.project.clone() else {
 9874            return;
 9875        };
 9876        self.reload(project, window, cx)
 9877            .detach_and_notify_err(window, cx);
 9878    }
 9879
 9880    pub fn restore_file(
 9881        &mut self,
 9882        _: &::git::RestoreFile,
 9883        window: &mut Window,
 9884        cx: &mut Context<Self>,
 9885    ) {
 9886        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9887        let mut buffer_ids = HashSet::default();
 9888        let snapshot = self.buffer().read(cx).snapshot(cx);
 9889        for selection in self.selections.all::<usize>(cx) {
 9890            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9891        }
 9892
 9893        let buffer = self.buffer().read(cx);
 9894        let ranges = buffer_ids
 9895            .into_iter()
 9896            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9897            .collect::<Vec<_>>();
 9898
 9899        self.restore_hunks_in_ranges(ranges, window, cx);
 9900    }
 9901
 9902    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9903        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9904        let selections = self
 9905            .selections
 9906            .all(cx)
 9907            .into_iter()
 9908            .map(|s| s.range())
 9909            .collect();
 9910        self.restore_hunks_in_ranges(selections, window, cx);
 9911    }
 9912
 9913    pub fn restore_hunks_in_ranges(
 9914        &mut self,
 9915        ranges: Vec<Range<Point>>,
 9916        window: &mut Window,
 9917        cx: &mut Context<Editor>,
 9918    ) {
 9919        let mut revert_changes = HashMap::default();
 9920        let chunk_by = self
 9921            .snapshot(window, cx)
 9922            .hunks_for_ranges(ranges)
 9923            .into_iter()
 9924            .chunk_by(|hunk| hunk.buffer_id);
 9925        for (buffer_id, hunks) in &chunk_by {
 9926            let hunks = hunks.collect::<Vec<_>>();
 9927            for hunk in &hunks {
 9928                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9929            }
 9930            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9931        }
 9932        drop(chunk_by);
 9933        if !revert_changes.is_empty() {
 9934            self.transact(window, cx, |editor, window, cx| {
 9935                editor.restore(revert_changes, window, cx);
 9936            });
 9937        }
 9938    }
 9939
 9940    pub fn open_active_item_in_terminal(
 9941        &mut self,
 9942        _: &OpenInTerminal,
 9943        window: &mut Window,
 9944        cx: &mut Context<Self>,
 9945    ) {
 9946        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9947            let project_path = buffer.read(cx).project_path(cx)?;
 9948            let project = self.project.as_ref()?.read(cx);
 9949            let entry = project.entry_for_path(&project_path, cx)?;
 9950            let parent = match &entry.canonical_path {
 9951                Some(canonical_path) => canonical_path.to_path_buf(),
 9952                None => project.absolute_path(&project_path, cx)?,
 9953            }
 9954            .parent()?
 9955            .to_path_buf();
 9956            Some(parent)
 9957        }) {
 9958            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9959        }
 9960    }
 9961
 9962    fn set_breakpoint_context_menu(
 9963        &mut self,
 9964        display_row: DisplayRow,
 9965        position: Option<Anchor>,
 9966        clicked_point: gpui::Point<Pixels>,
 9967        window: &mut Window,
 9968        cx: &mut Context<Self>,
 9969    ) {
 9970        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9971            return;
 9972        }
 9973        let source = self
 9974            .buffer
 9975            .read(cx)
 9976            .snapshot(cx)
 9977            .anchor_before(Point::new(display_row.0, 0u32));
 9978
 9979        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9980
 9981        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9982            self,
 9983            source,
 9984            clicked_point,
 9985            context_menu,
 9986            window,
 9987            cx,
 9988        );
 9989    }
 9990
 9991    fn add_edit_breakpoint_block(
 9992        &mut self,
 9993        anchor: Anchor,
 9994        breakpoint: &Breakpoint,
 9995        edit_action: BreakpointPromptEditAction,
 9996        window: &mut Window,
 9997        cx: &mut Context<Self>,
 9998    ) {
 9999        let weak_editor = cx.weak_entity();
10000        let bp_prompt = cx.new(|cx| {
10001            BreakpointPromptEditor::new(
10002                weak_editor,
10003                anchor,
10004                breakpoint.clone(),
10005                edit_action,
10006                window,
10007                cx,
10008            )
10009        });
10010
10011        let height = bp_prompt.update(cx, |this, cx| {
10012            this.prompt
10013                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10014        });
10015        let cloned_prompt = bp_prompt.clone();
10016        let blocks = vec![BlockProperties {
10017            style: BlockStyle::Sticky,
10018            placement: BlockPlacement::Above(anchor),
10019            height: Some(height),
10020            render: Arc::new(move |cx| {
10021                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10022                cloned_prompt.clone().into_any_element()
10023            }),
10024            priority: 0,
10025            render_in_minimap: true,
10026        }];
10027
10028        let focus_handle = bp_prompt.focus_handle(cx);
10029        window.focus(&focus_handle);
10030
10031        let block_ids = self.insert_blocks(blocks, None, cx);
10032        bp_prompt.update(cx, |prompt, _| {
10033            prompt.add_block_ids(block_ids);
10034        });
10035    }
10036
10037    pub(crate) fn breakpoint_at_row(
10038        &self,
10039        row: u32,
10040        window: &mut Window,
10041        cx: &mut Context<Self>,
10042    ) -> Option<(Anchor, Breakpoint)> {
10043        let snapshot = self.snapshot(window, cx);
10044        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10045
10046        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10047    }
10048
10049    pub(crate) fn breakpoint_at_anchor(
10050        &self,
10051        breakpoint_position: Anchor,
10052        snapshot: &EditorSnapshot,
10053        cx: &mut Context<Self>,
10054    ) -> Option<(Anchor, Breakpoint)> {
10055        let project = self.project.clone()?;
10056
10057        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10058            snapshot
10059                .buffer_snapshot
10060                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10061        })?;
10062
10063        let enclosing_excerpt = breakpoint_position.excerpt_id;
10064        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10065        let buffer_snapshot = buffer.read(cx).snapshot();
10066
10067        let row = buffer_snapshot
10068            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10069            .row;
10070
10071        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10072        let anchor_end = snapshot
10073            .buffer_snapshot
10074            .anchor_after(Point::new(row, line_len));
10075
10076        let bp = self
10077            .breakpoint_store
10078            .as_ref()?
10079            .read_with(cx, |breakpoint_store, cx| {
10080                breakpoint_store
10081                    .breakpoints(
10082                        &buffer,
10083                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10084                        &buffer_snapshot,
10085                        cx,
10086                    )
10087                    .next()
10088                    .and_then(|(bp, _)| {
10089                        let breakpoint_row = buffer_snapshot
10090                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10091                            .row;
10092
10093                        if breakpoint_row == row {
10094                            snapshot
10095                                .buffer_snapshot
10096                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10097                                .map(|position| (position, bp.bp.clone()))
10098                        } else {
10099                            None
10100                        }
10101                    })
10102            });
10103        bp
10104    }
10105
10106    pub fn edit_log_breakpoint(
10107        &mut self,
10108        _: &EditLogBreakpoint,
10109        window: &mut Window,
10110        cx: &mut Context<Self>,
10111    ) {
10112        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10113            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10114                message: None,
10115                state: BreakpointState::Enabled,
10116                condition: None,
10117                hit_condition: None,
10118            });
10119
10120            self.add_edit_breakpoint_block(
10121                anchor,
10122                &breakpoint,
10123                BreakpointPromptEditAction::Log,
10124                window,
10125                cx,
10126            );
10127        }
10128    }
10129
10130    fn breakpoints_at_cursors(
10131        &self,
10132        window: &mut Window,
10133        cx: &mut Context<Self>,
10134    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10135        let snapshot = self.snapshot(window, cx);
10136        let cursors = self
10137            .selections
10138            .disjoint_anchors()
10139            .into_iter()
10140            .map(|selection| {
10141                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10142
10143                let breakpoint_position = self
10144                    .breakpoint_at_row(cursor_position.row, window, cx)
10145                    .map(|bp| bp.0)
10146                    .unwrap_or_else(|| {
10147                        snapshot
10148                            .display_snapshot
10149                            .buffer_snapshot
10150                            .anchor_after(Point::new(cursor_position.row, 0))
10151                    });
10152
10153                let breakpoint = self
10154                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10155                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10156
10157                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10158            })
10159            // 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.
10160            .collect::<HashMap<Anchor, _>>();
10161
10162        cursors.into_iter().collect()
10163    }
10164
10165    pub fn enable_breakpoint(
10166        &mut self,
10167        _: &crate::actions::EnableBreakpoint,
10168        window: &mut Window,
10169        cx: &mut Context<Self>,
10170    ) {
10171        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10172            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10173                continue;
10174            };
10175            self.edit_breakpoint_at_anchor(
10176                anchor,
10177                breakpoint,
10178                BreakpointEditAction::InvertState,
10179                cx,
10180            );
10181        }
10182    }
10183
10184    pub fn disable_breakpoint(
10185        &mut self,
10186        _: &crate::actions::DisableBreakpoint,
10187        window: &mut Window,
10188        cx: &mut Context<Self>,
10189    ) {
10190        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10191            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10192                continue;
10193            };
10194            self.edit_breakpoint_at_anchor(
10195                anchor,
10196                breakpoint,
10197                BreakpointEditAction::InvertState,
10198                cx,
10199            );
10200        }
10201    }
10202
10203    pub fn toggle_breakpoint(
10204        &mut self,
10205        _: &crate::actions::ToggleBreakpoint,
10206        window: &mut Window,
10207        cx: &mut Context<Self>,
10208    ) {
10209        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10210            if let Some(breakpoint) = breakpoint {
10211                self.edit_breakpoint_at_anchor(
10212                    anchor,
10213                    breakpoint,
10214                    BreakpointEditAction::Toggle,
10215                    cx,
10216                );
10217            } else {
10218                self.edit_breakpoint_at_anchor(
10219                    anchor,
10220                    Breakpoint::new_standard(),
10221                    BreakpointEditAction::Toggle,
10222                    cx,
10223                );
10224            }
10225        }
10226    }
10227
10228    pub fn edit_breakpoint_at_anchor(
10229        &mut self,
10230        breakpoint_position: Anchor,
10231        breakpoint: Breakpoint,
10232        edit_action: BreakpointEditAction,
10233        cx: &mut Context<Self>,
10234    ) {
10235        let Some(breakpoint_store) = &self.breakpoint_store else {
10236            return;
10237        };
10238
10239        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10240            if breakpoint_position == Anchor::min() {
10241                self.buffer()
10242                    .read(cx)
10243                    .excerpt_buffer_ids()
10244                    .into_iter()
10245                    .next()
10246            } else {
10247                None
10248            }
10249        }) else {
10250            return;
10251        };
10252
10253        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10254            return;
10255        };
10256
10257        breakpoint_store.update(cx, |breakpoint_store, cx| {
10258            breakpoint_store.toggle_breakpoint(
10259                buffer,
10260                BreakpointWithPosition {
10261                    position: breakpoint_position.text_anchor,
10262                    bp: breakpoint,
10263                },
10264                edit_action,
10265                cx,
10266            );
10267        });
10268
10269        cx.notify();
10270    }
10271
10272    #[cfg(any(test, feature = "test-support"))]
10273    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10274        self.breakpoint_store.clone()
10275    }
10276
10277    pub fn prepare_restore_change(
10278        &self,
10279        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10280        hunk: &MultiBufferDiffHunk,
10281        cx: &mut App,
10282    ) -> Option<()> {
10283        if hunk.is_created_file() {
10284            return None;
10285        }
10286        let buffer = self.buffer.read(cx);
10287        let diff = buffer.diff_for(hunk.buffer_id)?;
10288        let buffer = buffer.buffer(hunk.buffer_id)?;
10289        let buffer = buffer.read(cx);
10290        let original_text = diff
10291            .read(cx)
10292            .base_text()
10293            .as_rope()
10294            .slice(hunk.diff_base_byte_range.clone());
10295        let buffer_snapshot = buffer.snapshot();
10296        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10297        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10298            probe
10299                .0
10300                .start
10301                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10302                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10303        }) {
10304            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10305            Some(())
10306        } else {
10307            None
10308        }
10309    }
10310
10311    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10312        self.manipulate_lines(window, cx, |lines| lines.reverse())
10313    }
10314
10315    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10316        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10317    }
10318
10319    fn manipulate_lines<Fn>(
10320        &mut self,
10321        window: &mut Window,
10322        cx: &mut Context<Self>,
10323        mut callback: Fn,
10324    ) where
10325        Fn: FnMut(&mut Vec<&str>),
10326    {
10327        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10328
10329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10330        let buffer = self.buffer.read(cx).snapshot(cx);
10331
10332        let mut edits = Vec::new();
10333
10334        let selections = self.selections.all::<Point>(cx);
10335        let mut selections = selections.iter().peekable();
10336        let mut contiguous_row_selections = Vec::new();
10337        let mut new_selections = Vec::new();
10338        let mut added_lines = 0;
10339        let mut removed_lines = 0;
10340
10341        while let Some(selection) = selections.next() {
10342            let (start_row, end_row) = consume_contiguous_rows(
10343                &mut contiguous_row_selections,
10344                selection,
10345                &display_map,
10346                &mut selections,
10347            );
10348
10349            let start_point = Point::new(start_row.0, 0);
10350            let end_point = Point::new(
10351                end_row.previous_row().0,
10352                buffer.line_len(end_row.previous_row()),
10353            );
10354            let text = buffer
10355                .text_for_range(start_point..end_point)
10356                .collect::<String>();
10357
10358            let mut lines = text.split('\n').collect_vec();
10359
10360            let lines_before = lines.len();
10361            callback(&mut lines);
10362            let lines_after = lines.len();
10363
10364            edits.push((start_point..end_point, lines.join("\n")));
10365
10366            // Selections must change based on added and removed line count
10367            let start_row =
10368                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10369            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10370            new_selections.push(Selection {
10371                id: selection.id,
10372                start: start_row,
10373                end: end_row,
10374                goal: SelectionGoal::None,
10375                reversed: selection.reversed,
10376            });
10377
10378            if lines_after > lines_before {
10379                added_lines += lines_after - lines_before;
10380            } else if lines_before > lines_after {
10381                removed_lines += lines_before - lines_after;
10382            }
10383        }
10384
10385        self.transact(window, cx, |this, window, cx| {
10386            let buffer = this.buffer.update(cx, |buffer, cx| {
10387                buffer.edit(edits, None, cx);
10388                buffer.snapshot(cx)
10389            });
10390
10391            // Recalculate offsets on newly edited buffer
10392            let new_selections = new_selections
10393                .iter()
10394                .map(|s| {
10395                    let start_point = Point::new(s.start.0, 0);
10396                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10397                    Selection {
10398                        id: s.id,
10399                        start: buffer.point_to_offset(start_point),
10400                        end: buffer.point_to_offset(end_point),
10401                        goal: s.goal,
10402                        reversed: s.reversed,
10403                    }
10404                })
10405                .collect();
10406
10407            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10408                s.select(new_selections);
10409            });
10410
10411            this.request_autoscroll(Autoscroll::fit(), cx);
10412        });
10413    }
10414
10415    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10416        self.manipulate_text(window, cx, |text| {
10417            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10418            if has_upper_case_characters {
10419                text.to_lowercase()
10420            } else {
10421                text.to_uppercase()
10422            }
10423        })
10424    }
10425
10426    pub fn convert_to_upper_case(
10427        &mut self,
10428        _: &ConvertToUpperCase,
10429        window: &mut Window,
10430        cx: &mut Context<Self>,
10431    ) {
10432        self.manipulate_text(window, cx, |text| text.to_uppercase())
10433    }
10434
10435    pub fn convert_to_lower_case(
10436        &mut self,
10437        _: &ConvertToLowerCase,
10438        window: &mut Window,
10439        cx: &mut Context<Self>,
10440    ) {
10441        self.manipulate_text(window, cx, |text| text.to_lowercase())
10442    }
10443
10444    pub fn convert_to_title_case(
10445        &mut self,
10446        _: &ConvertToTitleCase,
10447        window: &mut Window,
10448        cx: &mut Context<Self>,
10449    ) {
10450        self.manipulate_text(window, cx, |text| {
10451            text.split('\n')
10452                .map(|line| line.to_case(Case::Title))
10453                .join("\n")
10454        })
10455    }
10456
10457    pub fn convert_to_snake_case(
10458        &mut self,
10459        _: &ConvertToSnakeCase,
10460        window: &mut Window,
10461        cx: &mut Context<Self>,
10462    ) {
10463        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10464    }
10465
10466    pub fn convert_to_kebab_case(
10467        &mut self,
10468        _: &ConvertToKebabCase,
10469        window: &mut Window,
10470        cx: &mut Context<Self>,
10471    ) {
10472        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10473    }
10474
10475    pub fn convert_to_upper_camel_case(
10476        &mut self,
10477        _: &ConvertToUpperCamelCase,
10478        window: &mut Window,
10479        cx: &mut Context<Self>,
10480    ) {
10481        self.manipulate_text(window, cx, |text| {
10482            text.split('\n')
10483                .map(|line| line.to_case(Case::UpperCamel))
10484                .join("\n")
10485        })
10486    }
10487
10488    pub fn convert_to_lower_camel_case(
10489        &mut self,
10490        _: &ConvertToLowerCamelCase,
10491        window: &mut Window,
10492        cx: &mut Context<Self>,
10493    ) {
10494        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10495    }
10496
10497    pub fn convert_to_opposite_case(
10498        &mut self,
10499        _: &ConvertToOppositeCase,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.manipulate_text(window, cx, |text| {
10504            text.chars()
10505                .fold(String::with_capacity(text.len()), |mut t, c| {
10506                    if c.is_uppercase() {
10507                        t.extend(c.to_lowercase());
10508                    } else {
10509                        t.extend(c.to_uppercase());
10510                    }
10511                    t
10512                })
10513        })
10514    }
10515
10516    pub fn convert_to_rot13(
10517        &mut self,
10518        _: &ConvertToRot13,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_text(window, cx, |text| {
10523            text.chars()
10524                .map(|c| match c {
10525                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10526                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10527                    _ => c,
10528                })
10529                .collect()
10530        })
10531    }
10532
10533    pub fn convert_to_rot47(
10534        &mut self,
10535        _: &ConvertToRot47,
10536        window: &mut Window,
10537        cx: &mut Context<Self>,
10538    ) {
10539        self.manipulate_text(window, cx, |text| {
10540            text.chars()
10541                .map(|c| {
10542                    let code_point = c as u32;
10543                    if code_point >= 33 && code_point <= 126 {
10544                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10545                    }
10546                    c
10547                })
10548                .collect()
10549        })
10550    }
10551
10552    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10553    where
10554        Fn: FnMut(&str) -> String,
10555    {
10556        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10557        let buffer = self.buffer.read(cx).snapshot(cx);
10558
10559        let mut new_selections = Vec::new();
10560        let mut edits = Vec::new();
10561        let mut selection_adjustment = 0i32;
10562
10563        for selection in self.selections.all::<usize>(cx) {
10564            let selection_is_empty = selection.is_empty();
10565
10566            let (start, end) = if selection_is_empty {
10567                let word_range = movement::surrounding_word(
10568                    &display_map,
10569                    selection.start.to_display_point(&display_map),
10570                );
10571                let start = word_range.start.to_offset(&display_map, Bias::Left);
10572                let end = word_range.end.to_offset(&display_map, Bias::Left);
10573                (start, end)
10574            } else {
10575                (selection.start, selection.end)
10576            };
10577
10578            let text = buffer.text_for_range(start..end).collect::<String>();
10579            let old_length = text.len() as i32;
10580            let text = callback(&text);
10581
10582            new_selections.push(Selection {
10583                start: (start as i32 - selection_adjustment) as usize,
10584                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10585                goal: SelectionGoal::None,
10586                ..selection
10587            });
10588
10589            selection_adjustment += old_length - text.len() as i32;
10590
10591            edits.push((start..end, text));
10592        }
10593
10594        self.transact(window, cx, |this, window, cx| {
10595            this.buffer.update(cx, |buffer, cx| {
10596                buffer.edit(edits, None, cx);
10597            });
10598
10599            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10600                s.select(new_selections);
10601            });
10602
10603            this.request_autoscroll(Autoscroll::fit(), cx);
10604        });
10605    }
10606
10607    pub fn move_selection_on_drop(
10608        &mut self,
10609        selection: &Selection<Anchor>,
10610        target: DisplayPoint,
10611        is_cut: bool,
10612        window: &mut Window,
10613        cx: &mut Context<Self>,
10614    ) {
10615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10616        let buffer = &display_map.buffer_snapshot;
10617        let mut edits = Vec::new();
10618        let insert_point = display_map
10619            .clip_point(target, Bias::Left)
10620            .to_point(&display_map);
10621        let text = buffer
10622            .text_for_range(selection.start..selection.end)
10623            .collect::<String>();
10624        if is_cut {
10625            edits.push(((selection.start..selection.end), String::new()));
10626        }
10627        let insert_anchor = buffer.anchor_before(insert_point);
10628        edits.push(((insert_anchor..insert_anchor), text));
10629        let last_edit_start = insert_anchor.bias_left(buffer);
10630        let last_edit_end = insert_anchor.bias_right(buffer);
10631        self.transact(window, cx, |this, window, cx| {
10632            this.buffer.update(cx, |buffer, cx| {
10633                buffer.edit(edits, None, cx);
10634            });
10635            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10636                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10637            });
10638        });
10639    }
10640
10641    pub fn clear_selection_drag_state(&mut self) {
10642        self.selection_drag_state = SelectionDragState::None;
10643    }
10644
10645    pub fn duplicate(
10646        &mut self,
10647        upwards: bool,
10648        whole_lines: bool,
10649        window: &mut Window,
10650        cx: &mut Context<Self>,
10651    ) {
10652        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10653
10654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10655        let buffer = &display_map.buffer_snapshot;
10656        let selections = self.selections.all::<Point>(cx);
10657
10658        let mut edits = Vec::new();
10659        let mut selections_iter = selections.iter().peekable();
10660        while let Some(selection) = selections_iter.next() {
10661            let mut rows = selection.spanned_rows(false, &display_map);
10662            // duplicate line-wise
10663            if whole_lines || selection.start == selection.end {
10664                // Avoid duplicating the same lines twice.
10665                while let Some(next_selection) = selections_iter.peek() {
10666                    let next_rows = next_selection.spanned_rows(false, &display_map);
10667                    if next_rows.start < rows.end {
10668                        rows.end = next_rows.end;
10669                        selections_iter.next().unwrap();
10670                    } else {
10671                        break;
10672                    }
10673                }
10674
10675                // Copy the text from the selected row region and splice it either at the start
10676                // or end of the region.
10677                let start = Point::new(rows.start.0, 0);
10678                let end = Point::new(
10679                    rows.end.previous_row().0,
10680                    buffer.line_len(rows.end.previous_row()),
10681                );
10682                let text = buffer
10683                    .text_for_range(start..end)
10684                    .chain(Some("\n"))
10685                    .collect::<String>();
10686                let insert_location = if upwards {
10687                    Point::new(rows.end.0, 0)
10688                } else {
10689                    start
10690                };
10691                edits.push((insert_location..insert_location, text));
10692            } else {
10693                // duplicate character-wise
10694                let start = selection.start;
10695                let end = selection.end;
10696                let text = buffer.text_for_range(start..end).collect::<String>();
10697                edits.push((selection.end..selection.end, text));
10698            }
10699        }
10700
10701        self.transact(window, cx, |this, _, cx| {
10702            this.buffer.update(cx, |buffer, cx| {
10703                buffer.edit(edits, None, cx);
10704            });
10705
10706            this.request_autoscroll(Autoscroll::fit(), cx);
10707        });
10708    }
10709
10710    pub fn duplicate_line_up(
10711        &mut self,
10712        _: &DuplicateLineUp,
10713        window: &mut Window,
10714        cx: &mut Context<Self>,
10715    ) {
10716        self.duplicate(true, true, window, cx);
10717    }
10718
10719    pub fn duplicate_line_down(
10720        &mut self,
10721        _: &DuplicateLineDown,
10722        window: &mut Window,
10723        cx: &mut Context<Self>,
10724    ) {
10725        self.duplicate(false, true, window, cx);
10726    }
10727
10728    pub fn duplicate_selection(
10729        &mut self,
10730        _: &DuplicateSelection,
10731        window: &mut Window,
10732        cx: &mut Context<Self>,
10733    ) {
10734        self.duplicate(false, false, window, cx);
10735    }
10736
10737    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10738        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10739
10740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10741        let buffer = self.buffer.read(cx).snapshot(cx);
10742
10743        let mut edits = Vec::new();
10744        let mut unfold_ranges = Vec::new();
10745        let mut refold_creases = Vec::new();
10746
10747        let selections = self.selections.all::<Point>(cx);
10748        let mut selections = selections.iter().peekable();
10749        let mut contiguous_row_selections = Vec::new();
10750        let mut new_selections = Vec::new();
10751
10752        while let Some(selection) = selections.next() {
10753            // Find all the selections that span a contiguous row range
10754            let (start_row, end_row) = consume_contiguous_rows(
10755                &mut contiguous_row_selections,
10756                selection,
10757                &display_map,
10758                &mut selections,
10759            );
10760
10761            // Move the text spanned by the row range to be before the line preceding the row range
10762            if start_row.0 > 0 {
10763                let range_to_move = Point::new(
10764                    start_row.previous_row().0,
10765                    buffer.line_len(start_row.previous_row()),
10766                )
10767                    ..Point::new(
10768                        end_row.previous_row().0,
10769                        buffer.line_len(end_row.previous_row()),
10770                    );
10771                let insertion_point = display_map
10772                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10773                    .0;
10774
10775                // Don't move lines across excerpts
10776                if buffer
10777                    .excerpt_containing(insertion_point..range_to_move.end)
10778                    .is_some()
10779                {
10780                    let text = buffer
10781                        .text_for_range(range_to_move.clone())
10782                        .flat_map(|s| s.chars())
10783                        .skip(1)
10784                        .chain(['\n'])
10785                        .collect::<String>();
10786
10787                    edits.push((
10788                        buffer.anchor_after(range_to_move.start)
10789                            ..buffer.anchor_before(range_to_move.end),
10790                        String::new(),
10791                    ));
10792                    let insertion_anchor = buffer.anchor_after(insertion_point);
10793                    edits.push((insertion_anchor..insertion_anchor, text));
10794
10795                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10796
10797                    // Move selections up
10798                    new_selections.extend(contiguous_row_selections.drain(..).map(
10799                        |mut selection| {
10800                            selection.start.row -= row_delta;
10801                            selection.end.row -= row_delta;
10802                            selection
10803                        },
10804                    ));
10805
10806                    // Move folds up
10807                    unfold_ranges.push(range_to_move.clone());
10808                    for fold in display_map.folds_in_range(
10809                        buffer.anchor_before(range_to_move.start)
10810                            ..buffer.anchor_after(range_to_move.end),
10811                    ) {
10812                        let mut start = fold.range.start.to_point(&buffer);
10813                        let mut end = fold.range.end.to_point(&buffer);
10814                        start.row -= row_delta;
10815                        end.row -= row_delta;
10816                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10817                    }
10818                }
10819            }
10820
10821            // If we didn't move line(s), preserve the existing selections
10822            new_selections.append(&mut contiguous_row_selections);
10823        }
10824
10825        self.transact(window, cx, |this, window, cx| {
10826            this.unfold_ranges(&unfold_ranges, true, true, cx);
10827            this.buffer.update(cx, |buffer, cx| {
10828                for (range, text) in edits {
10829                    buffer.edit([(range, text)], None, cx);
10830                }
10831            });
10832            this.fold_creases(refold_creases, true, window, cx);
10833            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10834                s.select(new_selections);
10835            })
10836        });
10837    }
10838
10839    pub fn move_line_down(
10840        &mut self,
10841        _: &MoveLineDown,
10842        window: &mut Window,
10843        cx: &mut Context<Self>,
10844    ) {
10845        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10846
10847        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10848        let buffer = self.buffer.read(cx).snapshot(cx);
10849
10850        let mut edits = Vec::new();
10851        let mut unfold_ranges = Vec::new();
10852        let mut refold_creases = Vec::new();
10853
10854        let selections = self.selections.all::<Point>(cx);
10855        let mut selections = selections.iter().peekable();
10856        let mut contiguous_row_selections = Vec::new();
10857        let mut new_selections = Vec::new();
10858
10859        while let Some(selection) = selections.next() {
10860            // Find all the selections that span a contiguous row range
10861            let (start_row, end_row) = consume_contiguous_rows(
10862                &mut contiguous_row_selections,
10863                selection,
10864                &display_map,
10865                &mut selections,
10866            );
10867
10868            // Move the text spanned by the row range to be after the last line of the row range
10869            if end_row.0 <= buffer.max_point().row {
10870                let range_to_move =
10871                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10872                let insertion_point = display_map
10873                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10874                    .0;
10875
10876                // Don't move lines across excerpt boundaries
10877                if buffer
10878                    .excerpt_containing(range_to_move.start..insertion_point)
10879                    .is_some()
10880                {
10881                    let mut text = String::from("\n");
10882                    text.extend(buffer.text_for_range(range_to_move.clone()));
10883                    text.pop(); // Drop trailing newline
10884                    edits.push((
10885                        buffer.anchor_after(range_to_move.start)
10886                            ..buffer.anchor_before(range_to_move.end),
10887                        String::new(),
10888                    ));
10889                    let insertion_anchor = buffer.anchor_after(insertion_point);
10890                    edits.push((insertion_anchor..insertion_anchor, text));
10891
10892                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10893
10894                    // Move selections down
10895                    new_selections.extend(contiguous_row_selections.drain(..).map(
10896                        |mut selection| {
10897                            selection.start.row += row_delta;
10898                            selection.end.row += row_delta;
10899                            selection
10900                        },
10901                    ));
10902
10903                    // Move folds down
10904                    unfold_ranges.push(range_to_move.clone());
10905                    for fold in display_map.folds_in_range(
10906                        buffer.anchor_before(range_to_move.start)
10907                            ..buffer.anchor_after(range_to_move.end),
10908                    ) {
10909                        let mut start = fold.range.start.to_point(&buffer);
10910                        let mut end = fold.range.end.to_point(&buffer);
10911                        start.row += row_delta;
10912                        end.row += row_delta;
10913                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10914                    }
10915                }
10916            }
10917
10918            // If we didn't move line(s), preserve the existing selections
10919            new_selections.append(&mut contiguous_row_selections);
10920        }
10921
10922        self.transact(window, cx, |this, window, cx| {
10923            this.unfold_ranges(&unfold_ranges, true, true, cx);
10924            this.buffer.update(cx, |buffer, cx| {
10925                for (range, text) in edits {
10926                    buffer.edit([(range, text)], None, cx);
10927                }
10928            });
10929            this.fold_creases(refold_creases, true, window, cx);
10930            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10931                s.select(new_selections)
10932            });
10933        });
10934    }
10935
10936    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10937        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10938        let text_layout_details = &self.text_layout_details(window);
10939        self.transact(window, cx, |this, window, cx| {
10940            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10941                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10942                s.move_with(|display_map, selection| {
10943                    if !selection.is_empty() {
10944                        return;
10945                    }
10946
10947                    let mut head = selection.head();
10948                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10949                    if head.column() == display_map.line_len(head.row()) {
10950                        transpose_offset = display_map
10951                            .buffer_snapshot
10952                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10953                    }
10954
10955                    if transpose_offset == 0 {
10956                        return;
10957                    }
10958
10959                    *head.column_mut() += 1;
10960                    head = display_map.clip_point(head, Bias::Right);
10961                    let goal = SelectionGoal::HorizontalPosition(
10962                        display_map
10963                            .x_for_display_point(head, text_layout_details)
10964                            .into(),
10965                    );
10966                    selection.collapse_to(head, goal);
10967
10968                    let transpose_start = display_map
10969                        .buffer_snapshot
10970                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10971                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10972                        let transpose_end = display_map
10973                            .buffer_snapshot
10974                            .clip_offset(transpose_offset + 1, Bias::Right);
10975                        if let Some(ch) =
10976                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10977                        {
10978                            edits.push((transpose_start..transpose_offset, String::new()));
10979                            edits.push((transpose_end..transpose_end, ch.to_string()));
10980                        }
10981                    }
10982                });
10983                edits
10984            });
10985            this.buffer
10986                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10987            let selections = this.selections.all::<usize>(cx);
10988            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10989                s.select(selections);
10990            });
10991        });
10992    }
10993
10994    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10995        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10996        self.rewrap_impl(RewrapOptions::default(), cx)
10997    }
10998
10999    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11000        let buffer = self.buffer.read(cx).snapshot(cx);
11001        let selections = self.selections.all::<Point>(cx);
11002
11003        // Shrink and split selections to respect paragraph boundaries.
11004        let ranges = selections.into_iter().flat_map(|selection| {
11005            let language_settings = buffer.language_settings_at(selection.head(), cx);
11006            let language_scope = buffer.language_scope_at(selection.head());
11007
11008            let Some(start_row) = (selection.start.row..=selection.end.row)
11009                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11010            else {
11011                return vec![];
11012            };
11013            let Some(end_row) = (selection.start.row..=selection.end.row)
11014                .rev()
11015                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11016            else {
11017                return vec![];
11018            };
11019
11020            let mut row = start_row;
11021            let mut ranges = Vec::new();
11022            while let Some(blank_row) =
11023                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11024            {
11025                let next_paragraph_start = (blank_row + 1..=end_row)
11026                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11027                    .unwrap();
11028                ranges.push((
11029                    language_settings.clone(),
11030                    language_scope.clone(),
11031                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11032                ));
11033                row = next_paragraph_start;
11034            }
11035            ranges.push((
11036                language_settings.clone(),
11037                language_scope.clone(),
11038                Point::new(row, 0)..Point::new(end_row, 0),
11039            ));
11040
11041            ranges
11042        });
11043
11044        let mut edits = Vec::new();
11045        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11046
11047        for (language_settings, language_scope, range) in ranges {
11048            let mut start_row = range.start.row;
11049            let mut end_row = range.end.row;
11050
11051            // Skip selections that overlap with a range that has already been rewrapped.
11052            let selection_range = start_row..end_row;
11053            if rewrapped_row_ranges
11054                .iter()
11055                .any(|range| range.overlaps(&selection_range))
11056            {
11057                continue;
11058            }
11059
11060            let tab_size = language_settings.tab_size;
11061
11062            // Since not all lines in the selection may be at the same indent
11063            // level, choose the indent size that is the most common between all
11064            // of the lines.
11065            //
11066            // If there is a tie, we use the deepest indent.
11067            let (indent_size, indent_end) = {
11068                let mut indent_size_occurrences = HashMap::default();
11069                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11070
11071                for row in start_row..=end_row {
11072                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11073                    rows_by_indent_size.entry(indent).or_default().push(row);
11074                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11075                }
11076
11077                let indent_size = indent_size_occurrences
11078                    .into_iter()
11079                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11080                    .map(|(indent, _)| indent)
11081                    .unwrap_or_default();
11082                let row = rows_by_indent_size[&indent_size][0];
11083                let indent_end = Point::new(row, indent_size.len);
11084
11085                (indent_size, indent_end)
11086            };
11087
11088            let mut line_prefix = indent_size.chars().collect::<String>();
11089
11090            let mut inside_comment = false;
11091            if let Some(comment_prefix) = language_scope.and_then(|language| {
11092                language
11093                    .line_comment_prefixes()
11094                    .iter()
11095                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11096                    .cloned()
11097            }) {
11098                line_prefix.push_str(&comment_prefix);
11099                inside_comment = true;
11100            }
11101
11102            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11103                RewrapBehavior::InComments => inside_comment,
11104                RewrapBehavior::InSelections => !range.is_empty(),
11105                RewrapBehavior::Anywhere => true,
11106            };
11107
11108            let should_rewrap = options.override_language_settings
11109                || allow_rewrap_based_on_language
11110                || self.hard_wrap.is_some();
11111            if !should_rewrap {
11112                continue;
11113            }
11114
11115            if range.is_empty() {
11116                'expand_upwards: while start_row > 0 {
11117                    let prev_row = start_row - 1;
11118                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11119                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11120                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11121                    {
11122                        start_row = prev_row;
11123                    } else {
11124                        break 'expand_upwards;
11125                    }
11126                }
11127
11128                'expand_downwards: while end_row < buffer.max_point().row {
11129                    let next_row = end_row + 1;
11130                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11131                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11132                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11133                    {
11134                        end_row = next_row;
11135                    } else {
11136                        break 'expand_downwards;
11137                    }
11138                }
11139            }
11140
11141            let start = Point::new(start_row, 0);
11142            let start_offset = start.to_offset(&buffer);
11143            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11144            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11145            let Some(lines_without_prefixes) = selection_text
11146                .lines()
11147                .map(|line| {
11148                    line.strip_prefix(&line_prefix)
11149                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11150                        .with_context(|| {
11151                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11152                        })
11153                })
11154                .collect::<Result<Vec<_>, _>>()
11155                .log_err()
11156            else {
11157                continue;
11158            };
11159
11160            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11161                buffer
11162                    .language_settings_at(Point::new(start_row, 0), cx)
11163                    .preferred_line_length as usize
11164            });
11165            let wrapped_text = wrap_with_prefix(
11166                line_prefix,
11167                lines_without_prefixes.join("\n"),
11168                wrap_column,
11169                tab_size,
11170                options.preserve_existing_whitespace,
11171            );
11172
11173            // TODO: should always use char-based diff while still supporting cursor behavior that
11174            // matches vim.
11175            let mut diff_options = DiffOptions::default();
11176            if options.override_language_settings {
11177                diff_options.max_word_diff_len = 0;
11178                diff_options.max_word_diff_line_count = 0;
11179            } else {
11180                diff_options.max_word_diff_len = usize::MAX;
11181                diff_options.max_word_diff_line_count = usize::MAX;
11182            }
11183
11184            for (old_range, new_text) in
11185                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11186            {
11187                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11188                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11189                edits.push((edit_start..edit_end, new_text));
11190            }
11191
11192            rewrapped_row_ranges.push(start_row..=end_row);
11193        }
11194
11195        self.buffer
11196            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11197    }
11198
11199    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11200        let mut text = String::new();
11201        let buffer = self.buffer.read(cx).snapshot(cx);
11202        let mut selections = self.selections.all::<Point>(cx);
11203        let mut clipboard_selections = Vec::with_capacity(selections.len());
11204        {
11205            let max_point = buffer.max_point();
11206            let mut is_first = true;
11207            for selection in &mut selections {
11208                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11209                if is_entire_line {
11210                    selection.start = Point::new(selection.start.row, 0);
11211                    if !selection.is_empty() && selection.end.column == 0 {
11212                        selection.end = cmp::min(max_point, selection.end);
11213                    } else {
11214                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11215                    }
11216                    selection.goal = SelectionGoal::None;
11217                }
11218                if is_first {
11219                    is_first = false;
11220                } else {
11221                    text += "\n";
11222                }
11223                let mut len = 0;
11224                for chunk in buffer.text_for_range(selection.start..selection.end) {
11225                    text.push_str(chunk);
11226                    len += chunk.len();
11227                }
11228                clipboard_selections.push(ClipboardSelection {
11229                    len,
11230                    is_entire_line,
11231                    first_line_indent: buffer
11232                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11233                        .len,
11234                });
11235            }
11236        }
11237
11238        self.transact(window, cx, |this, window, cx| {
11239            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11240                s.select(selections);
11241            });
11242            this.insert("", window, cx);
11243        });
11244        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11245    }
11246
11247    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11248        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11249        let item = self.cut_common(window, cx);
11250        cx.write_to_clipboard(item);
11251    }
11252
11253    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11254        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11255        self.change_selections(None, window, cx, |s| {
11256            s.move_with(|snapshot, sel| {
11257                if sel.is_empty() {
11258                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11259                }
11260            });
11261        });
11262        let item = self.cut_common(window, cx);
11263        cx.set_global(KillRing(item))
11264    }
11265
11266    pub fn kill_ring_yank(
11267        &mut self,
11268        _: &KillRingYank,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271    ) {
11272        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11273        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11274            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11275                (kill_ring.text().to_string(), kill_ring.metadata_json())
11276            } else {
11277                return;
11278            }
11279        } else {
11280            return;
11281        };
11282        self.do_paste(&text, metadata, false, window, cx);
11283    }
11284
11285    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11286        self.do_copy(true, cx);
11287    }
11288
11289    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11290        self.do_copy(false, cx);
11291    }
11292
11293    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11294        let selections = self.selections.all::<Point>(cx);
11295        let buffer = self.buffer.read(cx).read(cx);
11296        let mut text = String::new();
11297
11298        let mut clipboard_selections = Vec::with_capacity(selections.len());
11299        {
11300            let max_point = buffer.max_point();
11301            let mut is_first = true;
11302            for selection in &selections {
11303                let mut start = selection.start;
11304                let mut end = selection.end;
11305                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11306                if is_entire_line {
11307                    start = Point::new(start.row, 0);
11308                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11309                }
11310
11311                let mut trimmed_selections = Vec::new();
11312                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11313                    let row = MultiBufferRow(start.row);
11314                    let first_indent = buffer.indent_size_for_line(row);
11315                    if first_indent.len == 0 || start.column > first_indent.len {
11316                        trimmed_selections.push(start..end);
11317                    } else {
11318                        trimmed_selections.push(
11319                            Point::new(row.0, first_indent.len)
11320                                ..Point::new(row.0, buffer.line_len(row)),
11321                        );
11322                        for row in start.row + 1..=end.row {
11323                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11324                            if row == end.row {
11325                                line_len = end.column;
11326                            }
11327                            if line_len == 0 {
11328                                trimmed_selections
11329                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11330                                continue;
11331                            }
11332                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11333                            if row_indent_size.len >= first_indent.len {
11334                                trimmed_selections.push(
11335                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11336                                );
11337                            } else {
11338                                trimmed_selections.clear();
11339                                trimmed_selections.push(start..end);
11340                                break;
11341                            }
11342                        }
11343                    }
11344                } else {
11345                    trimmed_selections.push(start..end);
11346                }
11347
11348                for trimmed_range in trimmed_selections {
11349                    if is_first {
11350                        is_first = false;
11351                    } else {
11352                        text += "\n";
11353                    }
11354                    let mut len = 0;
11355                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11356                        text.push_str(chunk);
11357                        len += chunk.len();
11358                    }
11359                    clipboard_selections.push(ClipboardSelection {
11360                        len,
11361                        is_entire_line,
11362                        first_line_indent: buffer
11363                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11364                            .len,
11365                    });
11366                }
11367            }
11368        }
11369
11370        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11371            text,
11372            clipboard_selections,
11373        ));
11374    }
11375
11376    pub fn do_paste(
11377        &mut self,
11378        text: &String,
11379        clipboard_selections: Option<Vec<ClipboardSelection>>,
11380        handle_entire_lines: bool,
11381        window: &mut Window,
11382        cx: &mut Context<Self>,
11383    ) {
11384        if self.read_only(cx) {
11385            return;
11386        }
11387
11388        let clipboard_text = Cow::Borrowed(text);
11389
11390        self.transact(window, cx, |this, window, cx| {
11391            if let Some(mut clipboard_selections) = clipboard_selections {
11392                let old_selections = this.selections.all::<usize>(cx);
11393                let all_selections_were_entire_line =
11394                    clipboard_selections.iter().all(|s| s.is_entire_line);
11395                let first_selection_indent_column =
11396                    clipboard_selections.first().map(|s| s.first_line_indent);
11397                if clipboard_selections.len() != old_selections.len() {
11398                    clipboard_selections.drain(..);
11399                }
11400                let cursor_offset = this.selections.last::<usize>(cx).head();
11401                let mut auto_indent_on_paste = true;
11402
11403                this.buffer.update(cx, |buffer, cx| {
11404                    let snapshot = buffer.read(cx);
11405                    auto_indent_on_paste = snapshot
11406                        .language_settings_at(cursor_offset, cx)
11407                        .auto_indent_on_paste;
11408
11409                    let mut start_offset = 0;
11410                    let mut edits = Vec::new();
11411                    let mut original_indent_columns = Vec::new();
11412                    for (ix, selection) in old_selections.iter().enumerate() {
11413                        let to_insert;
11414                        let entire_line;
11415                        let original_indent_column;
11416                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11417                            let end_offset = start_offset + clipboard_selection.len;
11418                            to_insert = &clipboard_text[start_offset..end_offset];
11419                            entire_line = clipboard_selection.is_entire_line;
11420                            start_offset = end_offset + 1;
11421                            original_indent_column = Some(clipboard_selection.first_line_indent);
11422                        } else {
11423                            to_insert = clipboard_text.as_str();
11424                            entire_line = all_selections_were_entire_line;
11425                            original_indent_column = first_selection_indent_column
11426                        }
11427
11428                        // If the corresponding selection was empty when this slice of the
11429                        // clipboard text was written, then the entire line containing the
11430                        // selection was copied. If this selection is also currently empty,
11431                        // then paste the line before the current line of the buffer.
11432                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11433                            let column = selection.start.to_point(&snapshot).column as usize;
11434                            let line_start = selection.start - column;
11435                            line_start..line_start
11436                        } else {
11437                            selection.range()
11438                        };
11439
11440                        edits.push((range, to_insert));
11441                        original_indent_columns.push(original_indent_column);
11442                    }
11443                    drop(snapshot);
11444
11445                    buffer.edit(
11446                        edits,
11447                        if auto_indent_on_paste {
11448                            Some(AutoindentMode::Block {
11449                                original_indent_columns,
11450                            })
11451                        } else {
11452                            None
11453                        },
11454                        cx,
11455                    );
11456                });
11457
11458                let selections = this.selections.all::<usize>(cx);
11459                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11460                    s.select(selections)
11461                });
11462            } else {
11463                this.insert(&clipboard_text, window, cx);
11464            }
11465        });
11466    }
11467
11468    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11469        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11470        if let Some(item) = cx.read_from_clipboard() {
11471            let entries = item.entries();
11472
11473            match entries.first() {
11474                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11475                // of all the pasted entries.
11476                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11477                    .do_paste(
11478                        clipboard_string.text(),
11479                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11480                        true,
11481                        window,
11482                        cx,
11483                    ),
11484                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11485            }
11486        }
11487    }
11488
11489    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11490        if self.read_only(cx) {
11491            return;
11492        }
11493
11494        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11495
11496        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11497            if let Some((selections, _)) =
11498                self.selection_history.transaction(transaction_id).cloned()
11499            {
11500                self.change_selections(None, window, cx, |s| {
11501                    s.select_anchors(selections.to_vec());
11502                });
11503            } else {
11504                log::error!(
11505                    "No entry in selection_history found for undo. \
11506                     This may correspond to a bug where undo does not update the selection. \
11507                     If this is occurring, please add details to \
11508                     https://github.com/zed-industries/zed/issues/22692"
11509                );
11510            }
11511            self.request_autoscroll(Autoscroll::fit(), cx);
11512            self.unmark_text(window, cx);
11513            self.refresh_inline_completion(true, false, window, cx);
11514            cx.emit(EditorEvent::Edited { transaction_id });
11515            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11516        }
11517    }
11518
11519    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11520        if self.read_only(cx) {
11521            return;
11522        }
11523
11524        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11525
11526        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11527            if let Some((_, Some(selections))) =
11528                self.selection_history.transaction(transaction_id).cloned()
11529            {
11530                self.change_selections(None, window, cx, |s| {
11531                    s.select_anchors(selections.to_vec());
11532                });
11533            } else {
11534                log::error!(
11535                    "No entry in selection_history found for redo. \
11536                     This may correspond to a bug where undo does not update the selection. \
11537                     If this is occurring, please add details to \
11538                     https://github.com/zed-industries/zed/issues/22692"
11539                );
11540            }
11541            self.request_autoscroll(Autoscroll::fit(), cx);
11542            self.unmark_text(window, cx);
11543            self.refresh_inline_completion(true, false, window, cx);
11544            cx.emit(EditorEvent::Edited { transaction_id });
11545        }
11546    }
11547
11548    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11549        self.buffer
11550            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11551    }
11552
11553    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11554        self.buffer
11555            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11556    }
11557
11558    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11559        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11560        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11561            s.move_with(|map, selection| {
11562                let cursor = if selection.is_empty() {
11563                    movement::left(map, selection.start)
11564                } else {
11565                    selection.start
11566                };
11567                selection.collapse_to(cursor, SelectionGoal::None);
11568            });
11569        })
11570    }
11571
11572    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11573        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11574        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11575            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11576        })
11577    }
11578
11579    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11580        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11581        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11582            s.move_with(|map, selection| {
11583                let cursor = if selection.is_empty() {
11584                    movement::right(map, selection.end)
11585                } else {
11586                    selection.end
11587                };
11588                selection.collapse_to(cursor, SelectionGoal::None)
11589            });
11590        })
11591    }
11592
11593    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11594        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11595        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11596            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11597        })
11598    }
11599
11600    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11601        if self.take_rename(true, window, cx).is_some() {
11602            return;
11603        }
11604
11605        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11606            cx.propagate();
11607            return;
11608        }
11609
11610        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11611
11612        let text_layout_details = &self.text_layout_details(window);
11613        let selection_count = self.selections.count();
11614        let first_selection = self.selections.first_anchor();
11615
11616        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11617            s.move_with(|map, selection| {
11618                if !selection.is_empty() {
11619                    selection.goal = SelectionGoal::None;
11620                }
11621                let (cursor, goal) = movement::up(
11622                    map,
11623                    selection.start,
11624                    selection.goal,
11625                    false,
11626                    text_layout_details,
11627                );
11628                selection.collapse_to(cursor, goal);
11629            });
11630        });
11631
11632        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11633        {
11634            cx.propagate();
11635        }
11636    }
11637
11638    pub fn move_up_by_lines(
11639        &mut self,
11640        action: &MoveUpByLines,
11641        window: &mut Window,
11642        cx: &mut Context<Self>,
11643    ) {
11644        if self.take_rename(true, window, cx).is_some() {
11645            return;
11646        }
11647
11648        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11649            cx.propagate();
11650            return;
11651        }
11652
11653        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11654
11655        let text_layout_details = &self.text_layout_details(window);
11656
11657        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658            s.move_with(|map, selection| {
11659                if !selection.is_empty() {
11660                    selection.goal = SelectionGoal::None;
11661                }
11662                let (cursor, goal) = movement::up_by_rows(
11663                    map,
11664                    selection.start,
11665                    action.lines,
11666                    selection.goal,
11667                    false,
11668                    text_layout_details,
11669                );
11670                selection.collapse_to(cursor, goal);
11671            });
11672        })
11673    }
11674
11675    pub fn move_down_by_lines(
11676        &mut self,
11677        action: &MoveDownByLines,
11678        window: &mut Window,
11679        cx: &mut Context<Self>,
11680    ) {
11681        if self.take_rename(true, window, cx).is_some() {
11682            return;
11683        }
11684
11685        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11686            cx.propagate();
11687            return;
11688        }
11689
11690        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11691
11692        let text_layout_details = &self.text_layout_details(window);
11693
11694        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11695            s.move_with(|map, selection| {
11696                if !selection.is_empty() {
11697                    selection.goal = SelectionGoal::None;
11698                }
11699                let (cursor, goal) = movement::down_by_rows(
11700                    map,
11701                    selection.start,
11702                    action.lines,
11703                    selection.goal,
11704                    false,
11705                    text_layout_details,
11706                );
11707                selection.collapse_to(cursor, goal);
11708            });
11709        })
11710    }
11711
11712    pub fn select_down_by_lines(
11713        &mut self,
11714        action: &SelectDownByLines,
11715        window: &mut Window,
11716        cx: &mut Context<Self>,
11717    ) {
11718        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11719        let text_layout_details = &self.text_layout_details(window);
11720        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11721            s.move_heads_with(|map, head, goal| {
11722                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11723            })
11724        })
11725    }
11726
11727    pub fn select_up_by_lines(
11728        &mut self,
11729        action: &SelectUpByLines,
11730        window: &mut Window,
11731        cx: &mut Context<Self>,
11732    ) {
11733        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11734        let text_layout_details = &self.text_layout_details(window);
11735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11736            s.move_heads_with(|map, head, goal| {
11737                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11738            })
11739        })
11740    }
11741
11742    pub fn select_page_up(
11743        &mut self,
11744        _: &SelectPageUp,
11745        window: &mut Window,
11746        cx: &mut Context<Self>,
11747    ) {
11748        let Some(row_count) = self.visible_row_count() else {
11749            return;
11750        };
11751
11752        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11753
11754        let text_layout_details = &self.text_layout_details(window);
11755
11756        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11757            s.move_heads_with(|map, head, goal| {
11758                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11759            })
11760        })
11761    }
11762
11763    pub fn move_page_up(
11764        &mut self,
11765        action: &MovePageUp,
11766        window: &mut Window,
11767        cx: &mut Context<Self>,
11768    ) {
11769        if self.take_rename(true, window, cx).is_some() {
11770            return;
11771        }
11772
11773        if self
11774            .context_menu
11775            .borrow_mut()
11776            .as_mut()
11777            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11778            .unwrap_or(false)
11779        {
11780            return;
11781        }
11782
11783        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11784            cx.propagate();
11785            return;
11786        }
11787
11788        let Some(row_count) = self.visible_row_count() else {
11789            return;
11790        };
11791
11792        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11793
11794        let autoscroll = if action.center_cursor {
11795            Autoscroll::center()
11796        } else {
11797            Autoscroll::fit()
11798        };
11799
11800        let text_layout_details = &self.text_layout_details(window);
11801
11802        self.change_selections(Some(autoscroll), window, cx, |s| {
11803            s.move_with(|map, selection| {
11804                if !selection.is_empty() {
11805                    selection.goal = SelectionGoal::None;
11806                }
11807                let (cursor, goal) = movement::up_by_rows(
11808                    map,
11809                    selection.end,
11810                    row_count,
11811                    selection.goal,
11812                    false,
11813                    text_layout_details,
11814                );
11815                selection.collapse_to(cursor, goal);
11816            });
11817        });
11818    }
11819
11820    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11821        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11822        let text_layout_details = &self.text_layout_details(window);
11823        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11824            s.move_heads_with(|map, head, goal| {
11825                movement::up(map, head, goal, false, text_layout_details)
11826            })
11827        })
11828    }
11829
11830    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11831        self.take_rename(true, window, cx);
11832
11833        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11834            cx.propagate();
11835            return;
11836        }
11837
11838        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11839
11840        let text_layout_details = &self.text_layout_details(window);
11841        let selection_count = self.selections.count();
11842        let first_selection = self.selections.first_anchor();
11843
11844        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11845            s.move_with(|map, selection| {
11846                if !selection.is_empty() {
11847                    selection.goal = SelectionGoal::None;
11848                }
11849                let (cursor, goal) = movement::down(
11850                    map,
11851                    selection.end,
11852                    selection.goal,
11853                    false,
11854                    text_layout_details,
11855                );
11856                selection.collapse_to(cursor, goal);
11857            });
11858        });
11859
11860        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11861        {
11862            cx.propagate();
11863        }
11864    }
11865
11866    pub fn select_page_down(
11867        &mut self,
11868        _: &SelectPageDown,
11869        window: &mut Window,
11870        cx: &mut Context<Self>,
11871    ) {
11872        let Some(row_count) = self.visible_row_count() else {
11873            return;
11874        };
11875
11876        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11877
11878        let text_layout_details = &self.text_layout_details(window);
11879
11880        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11881            s.move_heads_with(|map, head, goal| {
11882                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11883            })
11884        })
11885    }
11886
11887    pub fn move_page_down(
11888        &mut self,
11889        action: &MovePageDown,
11890        window: &mut Window,
11891        cx: &mut Context<Self>,
11892    ) {
11893        if self.take_rename(true, window, cx).is_some() {
11894            return;
11895        }
11896
11897        if self
11898            .context_menu
11899            .borrow_mut()
11900            .as_mut()
11901            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11902            .unwrap_or(false)
11903        {
11904            return;
11905        }
11906
11907        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11908            cx.propagate();
11909            return;
11910        }
11911
11912        let Some(row_count) = self.visible_row_count() else {
11913            return;
11914        };
11915
11916        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11917
11918        let autoscroll = if action.center_cursor {
11919            Autoscroll::center()
11920        } else {
11921            Autoscroll::fit()
11922        };
11923
11924        let text_layout_details = &self.text_layout_details(window);
11925        self.change_selections(Some(autoscroll), window, cx, |s| {
11926            s.move_with(|map, selection| {
11927                if !selection.is_empty() {
11928                    selection.goal = SelectionGoal::None;
11929                }
11930                let (cursor, goal) = movement::down_by_rows(
11931                    map,
11932                    selection.end,
11933                    row_count,
11934                    selection.goal,
11935                    false,
11936                    text_layout_details,
11937                );
11938                selection.collapse_to(cursor, goal);
11939            });
11940        });
11941    }
11942
11943    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11944        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11945        let text_layout_details = &self.text_layout_details(window);
11946        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11947            s.move_heads_with(|map, head, goal| {
11948                movement::down(map, head, goal, false, text_layout_details)
11949            })
11950        });
11951    }
11952
11953    pub fn context_menu_first(
11954        &mut self,
11955        _: &ContextMenuFirst,
11956        window: &mut Window,
11957        cx: &mut Context<Self>,
11958    ) {
11959        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11960            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11961        }
11962    }
11963
11964    pub fn context_menu_prev(
11965        &mut self,
11966        _: &ContextMenuPrevious,
11967        window: &mut Window,
11968        cx: &mut Context<Self>,
11969    ) {
11970        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11971            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11972        }
11973    }
11974
11975    pub fn context_menu_next(
11976        &mut self,
11977        _: &ContextMenuNext,
11978        window: &mut Window,
11979        cx: &mut Context<Self>,
11980    ) {
11981        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11982            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11983        }
11984    }
11985
11986    pub fn context_menu_last(
11987        &mut self,
11988        _: &ContextMenuLast,
11989        window: &mut Window,
11990        cx: &mut Context<Self>,
11991    ) {
11992        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11993            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11994        }
11995    }
11996
11997    pub fn move_to_previous_word_start(
11998        &mut self,
11999        _: &MoveToPreviousWordStart,
12000        window: &mut Window,
12001        cx: &mut Context<Self>,
12002    ) {
12003        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12004        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12005            s.move_cursors_with(|map, head, _| {
12006                (
12007                    movement::previous_word_start(map, head),
12008                    SelectionGoal::None,
12009                )
12010            });
12011        })
12012    }
12013
12014    pub fn move_to_previous_subword_start(
12015        &mut self,
12016        _: &MoveToPreviousSubwordStart,
12017        window: &mut Window,
12018        cx: &mut Context<Self>,
12019    ) {
12020        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12021        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12022            s.move_cursors_with(|map, head, _| {
12023                (
12024                    movement::previous_subword_start(map, head),
12025                    SelectionGoal::None,
12026                )
12027            });
12028        })
12029    }
12030
12031    pub fn select_to_previous_word_start(
12032        &mut self,
12033        _: &SelectToPreviousWordStart,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12038        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12039            s.move_heads_with(|map, head, _| {
12040                (
12041                    movement::previous_word_start(map, head),
12042                    SelectionGoal::None,
12043                )
12044            });
12045        })
12046    }
12047
12048    pub fn select_to_previous_subword_start(
12049        &mut self,
12050        _: &SelectToPreviousSubwordStart,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12055        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12056            s.move_heads_with(|map, head, _| {
12057                (
12058                    movement::previous_subword_start(map, head),
12059                    SelectionGoal::None,
12060                )
12061            });
12062        })
12063    }
12064
12065    pub fn delete_to_previous_word_start(
12066        &mut self,
12067        action: &DeleteToPreviousWordStart,
12068        window: &mut Window,
12069        cx: &mut Context<Self>,
12070    ) {
12071        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12072        self.transact(window, cx, |this, window, cx| {
12073            this.select_autoclose_pair(window, cx);
12074            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12075                s.move_with(|map, selection| {
12076                    if selection.is_empty() {
12077                        let cursor = if action.ignore_newlines {
12078                            movement::previous_word_start(map, selection.head())
12079                        } else {
12080                            movement::previous_word_start_or_newline(map, selection.head())
12081                        };
12082                        selection.set_head(cursor, SelectionGoal::None);
12083                    }
12084                });
12085            });
12086            this.insert("", window, cx);
12087        });
12088    }
12089
12090    pub fn delete_to_previous_subword_start(
12091        &mut self,
12092        _: &DeleteToPreviousSubwordStart,
12093        window: &mut Window,
12094        cx: &mut Context<Self>,
12095    ) {
12096        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12097        self.transact(window, cx, |this, window, cx| {
12098            this.select_autoclose_pair(window, cx);
12099            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12100                s.move_with(|map, selection| {
12101                    if selection.is_empty() {
12102                        let cursor = movement::previous_subword_start(map, selection.head());
12103                        selection.set_head(cursor, SelectionGoal::None);
12104                    }
12105                });
12106            });
12107            this.insert("", window, cx);
12108        });
12109    }
12110
12111    pub fn move_to_next_word_end(
12112        &mut self,
12113        _: &MoveToNextWordEnd,
12114        window: &mut Window,
12115        cx: &mut Context<Self>,
12116    ) {
12117        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12118        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12119            s.move_cursors_with(|map, head, _| {
12120                (movement::next_word_end(map, head), SelectionGoal::None)
12121            });
12122        })
12123    }
12124
12125    pub fn move_to_next_subword_end(
12126        &mut self,
12127        _: &MoveToNextSubwordEnd,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12132        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12133            s.move_cursors_with(|map, head, _| {
12134                (movement::next_subword_end(map, head), SelectionGoal::None)
12135            });
12136        })
12137    }
12138
12139    pub fn select_to_next_word_end(
12140        &mut self,
12141        _: &SelectToNextWordEnd,
12142        window: &mut Window,
12143        cx: &mut Context<Self>,
12144    ) {
12145        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12146        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12147            s.move_heads_with(|map, head, _| {
12148                (movement::next_word_end(map, head), SelectionGoal::None)
12149            });
12150        })
12151    }
12152
12153    pub fn select_to_next_subword_end(
12154        &mut self,
12155        _: &SelectToNextSubwordEnd,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12160        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12161            s.move_heads_with(|map, head, _| {
12162                (movement::next_subword_end(map, head), SelectionGoal::None)
12163            });
12164        })
12165    }
12166
12167    pub fn delete_to_next_word_end(
12168        &mut self,
12169        action: &DeleteToNextWordEnd,
12170        window: &mut Window,
12171        cx: &mut Context<Self>,
12172    ) {
12173        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12174        self.transact(window, cx, |this, window, cx| {
12175            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12176                s.move_with(|map, selection| {
12177                    if selection.is_empty() {
12178                        let cursor = if action.ignore_newlines {
12179                            movement::next_word_end(map, selection.head())
12180                        } else {
12181                            movement::next_word_end_or_newline(map, selection.head())
12182                        };
12183                        selection.set_head(cursor, SelectionGoal::None);
12184                    }
12185                });
12186            });
12187            this.insert("", window, cx);
12188        });
12189    }
12190
12191    pub fn delete_to_next_subword_end(
12192        &mut self,
12193        _: &DeleteToNextSubwordEnd,
12194        window: &mut Window,
12195        cx: &mut Context<Self>,
12196    ) {
12197        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12198        self.transact(window, cx, |this, window, cx| {
12199            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12200                s.move_with(|map, selection| {
12201                    if selection.is_empty() {
12202                        let cursor = movement::next_subword_end(map, selection.head());
12203                        selection.set_head(cursor, SelectionGoal::None);
12204                    }
12205                });
12206            });
12207            this.insert("", window, cx);
12208        });
12209    }
12210
12211    pub fn move_to_beginning_of_line(
12212        &mut self,
12213        action: &MoveToBeginningOfLine,
12214        window: &mut Window,
12215        cx: &mut Context<Self>,
12216    ) {
12217        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12218        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12219            s.move_cursors_with(|map, head, _| {
12220                (
12221                    movement::indented_line_beginning(
12222                        map,
12223                        head,
12224                        action.stop_at_soft_wraps,
12225                        action.stop_at_indent,
12226                    ),
12227                    SelectionGoal::None,
12228                )
12229            });
12230        })
12231    }
12232
12233    pub fn select_to_beginning_of_line(
12234        &mut self,
12235        action: &SelectToBeginningOfLine,
12236        window: &mut Window,
12237        cx: &mut Context<Self>,
12238    ) {
12239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12240        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12241            s.move_heads_with(|map, head, _| {
12242                (
12243                    movement::indented_line_beginning(
12244                        map,
12245                        head,
12246                        action.stop_at_soft_wraps,
12247                        action.stop_at_indent,
12248                    ),
12249                    SelectionGoal::None,
12250                )
12251            });
12252        });
12253    }
12254
12255    pub fn delete_to_beginning_of_line(
12256        &mut self,
12257        action: &DeleteToBeginningOfLine,
12258        window: &mut Window,
12259        cx: &mut Context<Self>,
12260    ) {
12261        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12262        self.transact(window, cx, |this, window, cx| {
12263            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12264                s.move_with(|_, selection| {
12265                    selection.reversed = true;
12266                });
12267            });
12268
12269            this.select_to_beginning_of_line(
12270                &SelectToBeginningOfLine {
12271                    stop_at_soft_wraps: false,
12272                    stop_at_indent: action.stop_at_indent,
12273                },
12274                window,
12275                cx,
12276            );
12277            this.backspace(&Backspace, window, cx);
12278        });
12279    }
12280
12281    pub fn move_to_end_of_line(
12282        &mut self,
12283        action: &MoveToEndOfLine,
12284        window: &mut Window,
12285        cx: &mut Context<Self>,
12286    ) {
12287        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12288        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12289            s.move_cursors_with(|map, head, _| {
12290                (
12291                    movement::line_end(map, head, action.stop_at_soft_wraps),
12292                    SelectionGoal::None,
12293                )
12294            });
12295        })
12296    }
12297
12298    pub fn select_to_end_of_line(
12299        &mut self,
12300        action: &SelectToEndOfLine,
12301        window: &mut Window,
12302        cx: &mut Context<Self>,
12303    ) {
12304        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12305        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12306            s.move_heads_with(|map, head, _| {
12307                (
12308                    movement::line_end(map, head, action.stop_at_soft_wraps),
12309                    SelectionGoal::None,
12310                )
12311            });
12312        })
12313    }
12314
12315    pub fn delete_to_end_of_line(
12316        &mut self,
12317        _: &DeleteToEndOfLine,
12318        window: &mut Window,
12319        cx: &mut Context<Self>,
12320    ) {
12321        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12322        self.transact(window, cx, |this, window, cx| {
12323            this.select_to_end_of_line(
12324                &SelectToEndOfLine {
12325                    stop_at_soft_wraps: false,
12326                },
12327                window,
12328                cx,
12329            );
12330            this.delete(&Delete, window, cx);
12331        });
12332    }
12333
12334    pub fn cut_to_end_of_line(
12335        &mut self,
12336        _: &CutToEndOfLine,
12337        window: &mut Window,
12338        cx: &mut Context<Self>,
12339    ) {
12340        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12341        self.transact(window, cx, |this, window, cx| {
12342            this.select_to_end_of_line(
12343                &SelectToEndOfLine {
12344                    stop_at_soft_wraps: false,
12345                },
12346                window,
12347                cx,
12348            );
12349            this.cut(&Cut, window, cx);
12350        });
12351    }
12352
12353    pub fn move_to_start_of_paragraph(
12354        &mut self,
12355        _: &MoveToStartOfParagraph,
12356        window: &mut Window,
12357        cx: &mut Context<Self>,
12358    ) {
12359        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12360            cx.propagate();
12361            return;
12362        }
12363        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12364        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12365            s.move_with(|map, selection| {
12366                selection.collapse_to(
12367                    movement::start_of_paragraph(map, selection.head(), 1),
12368                    SelectionGoal::None,
12369                )
12370            });
12371        })
12372    }
12373
12374    pub fn move_to_end_of_paragraph(
12375        &mut self,
12376        _: &MoveToEndOfParagraph,
12377        window: &mut Window,
12378        cx: &mut Context<Self>,
12379    ) {
12380        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12381            cx.propagate();
12382            return;
12383        }
12384        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12385        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12386            s.move_with(|map, selection| {
12387                selection.collapse_to(
12388                    movement::end_of_paragraph(map, selection.head(), 1),
12389                    SelectionGoal::None,
12390                )
12391            });
12392        })
12393    }
12394
12395    pub fn select_to_start_of_paragraph(
12396        &mut self,
12397        _: &SelectToStartOfParagraph,
12398        window: &mut Window,
12399        cx: &mut Context<Self>,
12400    ) {
12401        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12402            cx.propagate();
12403            return;
12404        }
12405        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12406        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12407            s.move_heads_with(|map, head, _| {
12408                (
12409                    movement::start_of_paragraph(map, head, 1),
12410                    SelectionGoal::None,
12411                )
12412            });
12413        })
12414    }
12415
12416    pub fn select_to_end_of_paragraph(
12417        &mut self,
12418        _: &SelectToEndOfParagraph,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12423            cx.propagate();
12424            return;
12425        }
12426        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12427        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12428            s.move_heads_with(|map, head, _| {
12429                (
12430                    movement::end_of_paragraph(map, head, 1),
12431                    SelectionGoal::None,
12432                )
12433            });
12434        })
12435    }
12436
12437    pub fn move_to_start_of_excerpt(
12438        &mut self,
12439        _: &MoveToStartOfExcerpt,
12440        window: &mut Window,
12441        cx: &mut Context<Self>,
12442    ) {
12443        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12444            cx.propagate();
12445            return;
12446        }
12447        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12448        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12449            s.move_with(|map, selection| {
12450                selection.collapse_to(
12451                    movement::start_of_excerpt(
12452                        map,
12453                        selection.head(),
12454                        workspace::searchable::Direction::Prev,
12455                    ),
12456                    SelectionGoal::None,
12457                )
12458            });
12459        })
12460    }
12461
12462    pub fn move_to_start_of_next_excerpt(
12463        &mut self,
12464        _: &MoveToStartOfNextExcerpt,
12465        window: &mut Window,
12466        cx: &mut Context<Self>,
12467    ) {
12468        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12469            cx.propagate();
12470            return;
12471        }
12472
12473        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12474            s.move_with(|map, selection| {
12475                selection.collapse_to(
12476                    movement::start_of_excerpt(
12477                        map,
12478                        selection.head(),
12479                        workspace::searchable::Direction::Next,
12480                    ),
12481                    SelectionGoal::None,
12482                )
12483            });
12484        })
12485    }
12486
12487    pub fn move_to_end_of_excerpt(
12488        &mut self,
12489        _: &MoveToEndOfExcerpt,
12490        window: &mut Window,
12491        cx: &mut Context<Self>,
12492    ) {
12493        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12494            cx.propagate();
12495            return;
12496        }
12497        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12498        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12499            s.move_with(|map, selection| {
12500                selection.collapse_to(
12501                    movement::end_of_excerpt(
12502                        map,
12503                        selection.head(),
12504                        workspace::searchable::Direction::Next,
12505                    ),
12506                    SelectionGoal::None,
12507                )
12508            });
12509        })
12510    }
12511
12512    pub fn move_to_end_of_previous_excerpt(
12513        &mut self,
12514        _: &MoveToEndOfPreviousExcerpt,
12515        window: &mut Window,
12516        cx: &mut Context<Self>,
12517    ) {
12518        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12519            cx.propagate();
12520            return;
12521        }
12522        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12523        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12524            s.move_with(|map, selection| {
12525                selection.collapse_to(
12526                    movement::end_of_excerpt(
12527                        map,
12528                        selection.head(),
12529                        workspace::searchable::Direction::Prev,
12530                    ),
12531                    SelectionGoal::None,
12532                )
12533            });
12534        })
12535    }
12536
12537    pub fn select_to_start_of_excerpt(
12538        &mut self,
12539        _: &SelectToStartOfExcerpt,
12540        window: &mut Window,
12541        cx: &mut Context<Self>,
12542    ) {
12543        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12544            cx.propagate();
12545            return;
12546        }
12547        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12548        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12549            s.move_heads_with(|map, head, _| {
12550                (
12551                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12552                    SelectionGoal::None,
12553                )
12554            });
12555        })
12556    }
12557
12558    pub fn select_to_start_of_next_excerpt(
12559        &mut self,
12560        _: &SelectToStartOfNextExcerpt,
12561        window: &mut Window,
12562        cx: &mut Context<Self>,
12563    ) {
12564        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12565            cx.propagate();
12566            return;
12567        }
12568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12569        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12570            s.move_heads_with(|map, head, _| {
12571                (
12572                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12573                    SelectionGoal::None,
12574                )
12575            });
12576        })
12577    }
12578
12579    pub fn select_to_end_of_excerpt(
12580        &mut self,
12581        _: &SelectToEndOfExcerpt,
12582        window: &mut Window,
12583        cx: &mut Context<Self>,
12584    ) {
12585        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12586            cx.propagate();
12587            return;
12588        }
12589        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12590        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12591            s.move_heads_with(|map, head, _| {
12592                (
12593                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12594                    SelectionGoal::None,
12595                )
12596            });
12597        })
12598    }
12599
12600    pub fn select_to_end_of_previous_excerpt(
12601        &mut self,
12602        _: &SelectToEndOfPreviousExcerpt,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12607            cx.propagate();
12608            return;
12609        }
12610        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12611        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12612            s.move_heads_with(|map, head, _| {
12613                (
12614                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12615                    SelectionGoal::None,
12616                )
12617            });
12618        })
12619    }
12620
12621    pub fn move_to_beginning(
12622        &mut self,
12623        _: &MoveToBeginning,
12624        window: &mut Window,
12625        cx: &mut Context<Self>,
12626    ) {
12627        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12628            cx.propagate();
12629            return;
12630        }
12631        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12632        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12633            s.select_ranges(vec![0..0]);
12634        });
12635    }
12636
12637    pub fn select_to_beginning(
12638        &mut self,
12639        _: &SelectToBeginning,
12640        window: &mut Window,
12641        cx: &mut Context<Self>,
12642    ) {
12643        let mut selection = self.selections.last::<Point>(cx);
12644        selection.set_head(Point::zero(), SelectionGoal::None);
12645        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12646        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12647            s.select(vec![selection]);
12648        });
12649    }
12650
12651    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12652        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12653            cx.propagate();
12654            return;
12655        }
12656        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12657        let cursor = self.buffer.read(cx).read(cx).len();
12658        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12659            s.select_ranges(vec![cursor..cursor])
12660        });
12661    }
12662
12663    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12664        self.nav_history = nav_history;
12665    }
12666
12667    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12668        self.nav_history.as_ref()
12669    }
12670
12671    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12672        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12673    }
12674
12675    fn push_to_nav_history(
12676        &mut self,
12677        cursor_anchor: Anchor,
12678        new_position: Option<Point>,
12679        is_deactivate: bool,
12680        cx: &mut Context<Self>,
12681    ) {
12682        if let Some(nav_history) = self.nav_history.as_mut() {
12683            let buffer = self.buffer.read(cx).read(cx);
12684            let cursor_position = cursor_anchor.to_point(&buffer);
12685            let scroll_state = self.scroll_manager.anchor();
12686            let scroll_top_row = scroll_state.top_row(&buffer);
12687            drop(buffer);
12688
12689            if let Some(new_position) = new_position {
12690                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12691                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12692                    return;
12693                }
12694            }
12695
12696            nav_history.push(
12697                Some(NavigationData {
12698                    cursor_anchor,
12699                    cursor_position,
12700                    scroll_anchor: scroll_state,
12701                    scroll_top_row,
12702                }),
12703                cx,
12704            );
12705            cx.emit(EditorEvent::PushedToNavHistory {
12706                anchor: cursor_anchor,
12707                is_deactivate,
12708            })
12709        }
12710    }
12711
12712    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12713        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12714        let buffer = self.buffer.read(cx).snapshot(cx);
12715        let mut selection = self.selections.first::<usize>(cx);
12716        selection.set_head(buffer.len(), SelectionGoal::None);
12717        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12718            s.select(vec![selection]);
12719        });
12720    }
12721
12722    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12723        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12724        let end = self.buffer.read(cx).read(cx).len();
12725        self.change_selections(None, window, cx, |s| {
12726            s.select_ranges(vec![0..end]);
12727        });
12728    }
12729
12730    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12732        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12733        let mut selections = self.selections.all::<Point>(cx);
12734        let max_point = display_map.buffer_snapshot.max_point();
12735        for selection in &mut selections {
12736            let rows = selection.spanned_rows(true, &display_map);
12737            selection.start = Point::new(rows.start.0, 0);
12738            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12739            selection.reversed = false;
12740        }
12741        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12742            s.select(selections);
12743        });
12744    }
12745
12746    pub fn split_selection_into_lines(
12747        &mut self,
12748        _: &SplitSelectionIntoLines,
12749        window: &mut Window,
12750        cx: &mut Context<Self>,
12751    ) {
12752        let selections = self
12753            .selections
12754            .all::<Point>(cx)
12755            .into_iter()
12756            .map(|selection| selection.start..selection.end)
12757            .collect::<Vec<_>>();
12758        self.unfold_ranges(&selections, true, true, cx);
12759
12760        let mut new_selection_ranges = Vec::new();
12761        {
12762            let buffer = self.buffer.read(cx).read(cx);
12763            for selection in selections {
12764                for row in selection.start.row..selection.end.row {
12765                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12766                    new_selection_ranges.push(cursor..cursor);
12767                }
12768
12769                let is_multiline_selection = selection.start.row != selection.end.row;
12770                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12771                // so this action feels more ergonomic when paired with other selection operations
12772                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12773                if !should_skip_last {
12774                    new_selection_ranges.push(selection.end..selection.end);
12775                }
12776            }
12777        }
12778        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12779            s.select_ranges(new_selection_ranges);
12780        });
12781    }
12782
12783    pub fn add_selection_above(
12784        &mut self,
12785        _: &AddSelectionAbove,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        self.add_selection(true, window, cx);
12790    }
12791
12792    pub fn add_selection_below(
12793        &mut self,
12794        _: &AddSelectionBelow,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        self.add_selection(false, window, cx);
12799    }
12800
12801    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12802        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12803
12804        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12805        let all_selections = self.selections.all::<Point>(cx);
12806        let text_layout_details = self.text_layout_details(window);
12807
12808        let (mut columnar_selections, new_selections_to_columnarize) = {
12809            if let Some(state) = self.add_selections_state.as_ref() {
12810                let columnar_selection_ids: HashSet<_> = state
12811                    .groups
12812                    .iter()
12813                    .flat_map(|group| group.stack.iter())
12814                    .copied()
12815                    .collect();
12816
12817                all_selections
12818                    .into_iter()
12819                    .partition(|s| columnar_selection_ids.contains(&s.id))
12820            } else {
12821                (Vec::new(), all_selections)
12822            }
12823        };
12824
12825        let mut state = self
12826            .add_selections_state
12827            .take()
12828            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12829
12830        for selection in new_selections_to_columnarize {
12831            let range = selection.display_range(&display_map).sorted();
12832            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12833            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12834            let positions = start_x.min(end_x)..start_x.max(end_x);
12835            let mut stack = Vec::new();
12836            for row in range.start.row().0..=range.end.row().0 {
12837                if let Some(selection) = self.selections.build_columnar_selection(
12838                    &display_map,
12839                    DisplayRow(row),
12840                    &positions,
12841                    selection.reversed,
12842                    &text_layout_details,
12843                ) {
12844                    stack.push(selection.id);
12845                    columnar_selections.push(selection);
12846                }
12847            }
12848            if !stack.is_empty() {
12849                if above {
12850                    stack.reverse();
12851                }
12852                state.groups.push(AddSelectionsGroup { above, stack });
12853            }
12854        }
12855
12856        let mut final_selections = Vec::new();
12857        let end_row = if above {
12858            DisplayRow(0)
12859        } else {
12860            display_map.max_point().row()
12861        };
12862
12863        let mut last_added_item_per_group = HashMap::default();
12864        for group in state.groups.iter_mut() {
12865            if let Some(last_id) = group.stack.last() {
12866                last_added_item_per_group.insert(*last_id, group);
12867            }
12868        }
12869
12870        for selection in columnar_selections {
12871            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12872                if above == group.above {
12873                    let range = selection.display_range(&display_map).sorted();
12874                    debug_assert_eq!(range.start.row(), range.end.row());
12875                    let mut row = range.start.row();
12876                    let positions =
12877                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12878                            px(start)..px(end)
12879                        } else {
12880                            let start_x =
12881                                display_map.x_for_display_point(range.start, &text_layout_details);
12882                            let end_x =
12883                                display_map.x_for_display_point(range.end, &text_layout_details);
12884                            start_x.min(end_x)..start_x.max(end_x)
12885                        };
12886
12887                    let mut maybe_new_selection = None;
12888                    while row != end_row {
12889                        if above {
12890                            row.0 -= 1;
12891                        } else {
12892                            row.0 += 1;
12893                        }
12894                        if let Some(new_selection) = self.selections.build_columnar_selection(
12895                            &display_map,
12896                            row,
12897                            &positions,
12898                            selection.reversed,
12899                            &text_layout_details,
12900                        ) {
12901                            maybe_new_selection = Some(new_selection);
12902                            break;
12903                        }
12904                    }
12905
12906                    if let Some(new_selection) = maybe_new_selection {
12907                        group.stack.push(new_selection.id);
12908                        if above {
12909                            final_selections.push(new_selection);
12910                            final_selections.push(selection);
12911                        } else {
12912                            final_selections.push(selection);
12913                            final_selections.push(new_selection);
12914                        }
12915                    } else {
12916                        final_selections.push(selection);
12917                    }
12918                } else {
12919                    group.stack.pop();
12920                }
12921            } else {
12922                final_selections.push(selection);
12923            }
12924        }
12925
12926        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12927            s.select(final_selections);
12928        });
12929
12930        let final_selection_ids: HashSet<_> = self
12931            .selections
12932            .all::<Point>(cx)
12933            .iter()
12934            .map(|s| s.id)
12935            .collect();
12936        state.groups.retain_mut(|group| {
12937            // selections might get merged above so we remove invalid items from stacks
12938            group.stack.retain(|id| final_selection_ids.contains(id));
12939
12940            // single selection in stack can be treated as initial state
12941            group.stack.len() > 1
12942        });
12943
12944        if !state.groups.is_empty() {
12945            self.add_selections_state = Some(state);
12946        }
12947    }
12948
12949    fn select_match_ranges(
12950        &mut self,
12951        range: Range<usize>,
12952        reversed: bool,
12953        replace_newest: bool,
12954        auto_scroll: Option<Autoscroll>,
12955        window: &mut Window,
12956        cx: &mut Context<Editor>,
12957    ) {
12958        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12959        self.change_selections(auto_scroll, window, cx, |s| {
12960            if replace_newest {
12961                s.delete(s.newest_anchor().id);
12962            }
12963            if reversed {
12964                s.insert_range(range.end..range.start);
12965            } else {
12966                s.insert_range(range);
12967            }
12968        });
12969    }
12970
12971    pub fn select_next_match_internal(
12972        &mut self,
12973        display_map: &DisplaySnapshot,
12974        replace_newest: bool,
12975        autoscroll: Option<Autoscroll>,
12976        window: &mut Window,
12977        cx: &mut Context<Self>,
12978    ) -> Result<()> {
12979        let buffer = &display_map.buffer_snapshot;
12980        let mut selections = self.selections.all::<usize>(cx);
12981        if let Some(mut select_next_state) = self.select_next_state.take() {
12982            let query = &select_next_state.query;
12983            if !select_next_state.done {
12984                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12985                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12986                let mut next_selected_range = None;
12987
12988                let bytes_after_last_selection =
12989                    buffer.bytes_in_range(last_selection.end..buffer.len());
12990                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12991                let query_matches = query
12992                    .stream_find_iter(bytes_after_last_selection)
12993                    .map(|result| (last_selection.end, result))
12994                    .chain(
12995                        query
12996                            .stream_find_iter(bytes_before_first_selection)
12997                            .map(|result| (0, result)),
12998                    );
12999
13000                for (start_offset, query_match) in query_matches {
13001                    let query_match = query_match.unwrap(); // can only fail due to I/O
13002                    let offset_range =
13003                        start_offset + query_match.start()..start_offset + query_match.end();
13004                    let display_range = offset_range.start.to_display_point(display_map)
13005                        ..offset_range.end.to_display_point(display_map);
13006
13007                    if !select_next_state.wordwise
13008                        || (!movement::is_inside_word(display_map, display_range.start)
13009                            && !movement::is_inside_word(display_map, display_range.end))
13010                    {
13011                        // TODO: This is n^2, because we might check all the selections
13012                        if !selections
13013                            .iter()
13014                            .any(|selection| selection.range().overlaps(&offset_range))
13015                        {
13016                            next_selected_range = Some(offset_range);
13017                            break;
13018                        }
13019                    }
13020                }
13021
13022                if let Some(next_selected_range) = next_selected_range {
13023                    self.select_match_ranges(
13024                        next_selected_range,
13025                        last_selection.reversed,
13026                        replace_newest,
13027                        autoscroll,
13028                        window,
13029                        cx,
13030                    );
13031                } else {
13032                    select_next_state.done = true;
13033                }
13034            }
13035
13036            self.select_next_state = Some(select_next_state);
13037        } else {
13038            let mut only_carets = true;
13039            let mut same_text_selected = true;
13040            let mut selected_text = None;
13041
13042            let mut selections_iter = selections.iter().peekable();
13043            while let Some(selection) = selections_iter.next() {
13044                if selection.start != selection.end {
13045                    only_carets = false;
13046                }
13047
13048                if same_text_selected {
13049                    if selected_text.is_none() {
13050                        selected_text =
13051                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13052                    }
13053
13054                    if let Some(next_selection) = selections_iter.peek() {
13055                        if next_selection.range().len() == selection.range().len() {
13056                            let next_selected_text = buffer
13057                                .text_for_range(next_selection.range())
13058                                .collect::<String>();
13059                            if Some(next_selected_text) != selected_text {
13060                                same_text_selected = false;
13061                                selected_text = None;
13062                            }
13063                        } else {
13064                            same_text_selected = false;
13065                            selected_text = None;
13066                        }
13067                    }
13068                }
13069            }
13070
13071            if only_carets {
13072                for selection in &mut selections {
13073                    let word_range = movement::surrounding_word(
13074                        display_map,
13075                        selection.start.to_display_point(display_map),
13076                    );
13077                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13078                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13079                    selection.goal = SelectionGoal::None;
13080                    selection.reversed = false;
13081                    self.select_match_ranges(
13082                        selection.start..selection.end,
13083                        selection.reversed,
13084                        replace_newest,
13085                        autoscroll,
13086                        window,
13087                        cx,
13088                    );
13089                }
13090
13091                if selections.len() == 1 {
13092                    let selection = selections
13093                        .last()
13094                        .expect("ensured that there's only one selection");
13095                    let query = buffer
13096                        .text_for_range(selection.start..selection.end)
13097                        .collect::<String>();
13098                    let is_empty = query.is_empty();
13099                    let select_state = SelectNextState {
13100                        query: AhoCorasick::new(&[query])?,
13101                        wordwise: true,
13102                        done: is_empty,
13103                    };
13104                    self.select_next_state = Some(select_state);
13105                } else {
13106                    self.select_next_state = None;
13107                }
13108            } else if let Some(selected_text) = selected_text {
13109                self.select_next_state = Some(SelectNextState {
13110                    query: AhoCorasick::new(&[selected_text])?,
13111                    wordwise: false,
13112                    done: false,
13113                });
13114                self.select_next_match_internal(
13115                    display_map,
13116                    replace_newest,
13117                    autoscroll,
13118                    window,
13119                    cx,
13120                )?;
13121            }
13122        }
13123        Ok(())
13124    }
13125
13126    pub fn select_all_matches(
13127        &mut self,
13128        _action: &SelectAllMatches,
13129        window: &mut Window,
13130        cx: &mut Context<Self>,
13131    ) -> Result<()> {
13132        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13133
13134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13135
13136        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13137        let Some(select_next_state) = self.select_next_state.as_mut() else {
13138            return Ok(());
13139        };
13140        if select_next_state.done {
13141            return Ok(());
13142        }
13143
13144        let mut new_selections = Vec::new();
13145
13146        let reversed = self.selections.oldest::<usize>(cx).reversed;
13147        let buffer = &display_map.buffer_snapshot;
13148        let query_matches = select_next_state
13149            .query
13150            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13151
13152        for query_match in query_matches.into_iter() {
13153            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13154            let offset_range = if reversed {
13155                query_match.end()..query_match.start()
13156            } else {
13157                query_match.start()..query_match.end()
13158            };
13159            let display_range = offset_range.start.to_display_point(&display_map)
13160                ..offset_range.end.to_display_point(&display_map);
13161
13162            if !select_next_state.wordwise
13163                || (!movement::is_inside_word(&display_map, display_range.start)
13164                    && !movement::is_inside_word(&display_map, display_range.end))
13165            {
13166                new_selections.push(offset_range.start..offset_range.end);
13167            }
13168        }
13169
13170        select_next_state.done = true;
13171        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13172        self.change_selections(None, window, cx, |selections| {
13173            selections.select_ranges(new_selections)
13174        });
13175
13176        Ok(())
13177    }
13178
13179    pub fn select_next(
13180        &mut self,
13181        action: &SelectNext,
13182        window: &mut Window,
13183        cx: &mut Context<Self>,
13184    ) -> Result<()> {
13185        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13186        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13187        self.select_next_match_internal(
13188            &display_map,
13189            action.replace_newest,
13190            Some(Autoscroll::newest()),
13191            window,
13192            cx,
13193        )?;
13194        Ok(())
13195    }
13196
13197    pub fn select_previous(
13198        &mut self,
13199        action: &SelectPrevious,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) -> Result<()> {
13203        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13205        let buffer = &display_map.buffer_snapshot;
13206        let mut selections = self.selections.all::<usize>(cx);
13207        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13208            let query = &select_prev_state.query;
13209            if !select_prev_state.done {
13210                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13211                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13212                let mut next_selected_range = None;
13213                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13214                let bytes_before_last_selection =
13215                    buffer.reversed_bytes_in_range(0..last_selection.start);
13216                let bytes_after_first_selection =
13217                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13218                let query_matches = query
13219                    .stream_find_iter(bytes_before_last_selection)
13220                    .map(|result| (last_selection.start, result))
13221                    .chain(
13222                        query
13223                            .stream_find_iter(bytes_after_first_selection)
13224                            .map(|result| (buffer.len(), result)),
13225                    );
13226                for (end_offset, query_match) in query_matches {
13227                    let query_match = query_match.unwrap(); // can only fail due to I/O
13228                    let offset_range =
13229                        end_offset - query_match.end()..end_offset - query_match.start();
13230                    let display_range = offset_range.start.to_display_point(&display_map)
13231                        ..offset_range.end.to_display_point(&display_map);
13232
13233                    if !select_prev_state.wordwise
13234                        || (!movement::is_inside_word(&display_map, display_range.start)
13235                            && !movement::is_inside_word(&display_map, display_range.end))
13236                    {
13237                        next_selected_range = Some(offset_range);
13238                        break;
13239                    }
13240                }
13241
13242                if let Some(next_selected_range) = next_selected_range {
13243                    self.select_match_ranges(
13244                        next_selected_range,
13245                        last_selection.reversed,
13246                        action.replace_newest,
13247                        Some(Autoscroll::newest()),
13248                        window,
13249                        cx,
13250                    );
13251                } else {
13252                    select_prev_state.done = true;
13253                }
13254            }
13255
13256            self.select_prev_state = Some(select_prev_state);
13257        } else {
13258            let mut only_carets = true;
13259            let mut same_text_selected = true;
13260            let mut selected_text = None;
13261
13262            let mut selections_iter = selections.iter().peekable();
13263            while let Some(selection) = selections_iter.next() {
13264                if selection.start != selection.end {
13265                    only_carets = false;
13266                }
13267
13268                if same_text_selected {
13269                    if selected_text.is_none() {
13270                        selected_text =
13271                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13272                    }
13273
13274                    if let Some(next_selection) = selections_iter.peek() {
13275                        if next_selection.range().len() == selection.range().len() {
13276                            let next_selected_text = buffer
13277                                .text_for_range(next_selection.range())
13278                                .collect::<String>();
13279                            if Some(next_selected_text) != selected_text {
13280                                same_text_selected = false;
13281                                selected_text = None;
13282                            }
13283                        } else {
13284                            same_text_selected = false;
13285                            selected_text = None;
13286                        }
13287                    }
13288                }
13289            }
13290
13291            if only_carets {
13292                for selection in &mut selections {
13293                    let word_range = movement::surrounding_word(
13294                        &display_map,
13295                        selection.start.to_display_point(&display_map),
13296                    );
13297                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13298                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13299                    selection.goal = SelectionGoal::None;
13300                    selection.reversed = false;
13301                    self.select_match_ranges(
13302                        selection.start..selection.end,
13303                        selection.reversed,
13304                        action.replace_newest,
13305                        Some(Autoscroll::newest()),
13306                        window,
13307                        cx,
13308                    );
13309                }
13310                if selections.len() == 1 {
13311                    let selection = selections
13312                        .last()
13313                        .expect("ensured that there's only one selection");
13314                    let query = buffer
13315                        .text_for_range(selection.start..selection.end)
13316                        .collect::<String>();
13317                    let is_empty = query.is_empty();
13318                    let select_state = SelectNextState {
13319                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13320                        wordwise: true,
13321                        done: is_empty,
13322                    };
13323                    self.select_prev_state = Some(select_state);
13324                } else {
13325                    self.select_prev_state = None;
13326                }
13327            } else if let Some(selected_text) = selected_text {
13328                self.select_prev_state = Some(SelectNextState {
13329                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13330                    wordwise: false,
13331                    done: false,
13332                });
13333                self.select_previous(action, window, cx)?;
13334            }
13335        }
13336        Ok(())
13337    }
13338
13339    pub fn find_next_match(
13340        &mut self,
13341        _: &FindNextMatch,
13342        window: &mut Window,
13343        cx: &mut Context<Self>,
13344    ) -> Result<()> {
13345        let selections = self.selections.disjoint_anchors();
13346        match selections.first() {
13347            Some(first) if selections.len() >= 2 => {
13348                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13349                    s.select_ranges([first.range()]);
13350                });
13351            }
13352            _ => self.select_next(
13353                &SelectNext {
13354                    replace_newest: true,
13355                },
13356                window,
13357                cx,
13358            )?,
13359        }
13360        Ok(())
13361    }
13362
13363    pub fn find_previous_match(
13364        &mut self,
13365        _: &FindPreviousMatch,
13366        window: &mut Window,
13367        cx: &mut Context<Self>,
13368    ) -> Result<()> {
13369        let selections = self.selections.disjoint_anchors();
13370        match selections.last() {
13371            Some(last) if selections.len() >= 2 => {
13372                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13373                    s.select_ranges([last.range()]);
13374                });
13375            }
13376            _ => self.select_previous(
13377                &SelectPrevious {
13378                    replace_newest: true,
13379                },
13380                window,
13381                cx,
13382            )?,
13383        }
13384        Ok(())
13385    }
13386
13387    pub fn toggle_comments(
13388        &mut self,
13389        action: &ToggleComments,
13390        window: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        if self.read_only(cx) {
13394            return;
13395        }
13396        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13397        let text_layout_details = &self.text_layout_details(window);
13398        self.transact(window, cx, |this, window, cx| {
13399            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13400            let mut edits = Vec::new();
13401            let mut selection_edit_ranges = Vec::new();
13402            let mut last_toggled_row = None;
13403            let snapshot = this.buffer.read(cx).read(cx);
13404            let empty_str: Arc<str> = Arc::default();
13405            let mut suffixes_inserted = Vec::new();
13406            let ignore_indent = action.ignore_indent;
13407
13408            fn comment_prefix_range(
13409                snapshot: &MultiBufferSnapshot,
13410                row: MultiBufferRow,
13411                comment_prefix: &str,
13412                comment_prefix_whitespace: &str,
13413                ignore_indent: bool,
13414            ) -> Range<Point> {
13415                let indent_size = if ignore_indent {
13416                    0
13417                } else {
13418                    snapshot.indent_size_for_line(row).len
13419                };
13420
13421                let start = Point::new(row.0, indent_size);
13422
13423                let mut line_bytes = snapshot
13424                    .bytes_in_range(start..snapshot.max_point())
13425                    .flatten()
13426                    .copied();
13427
13428                // If this line currently begins with the line comment prefix, then record
13429                // the range containing the prefix.
13430                if line_bytes
13431                    .by_ref()
13432                    .take(comment_prefix.len())
13433                    .eq(comment_prefix.bytes())
13434                {
13435                    // Include any whitespace that matches the comment prefix.
13436                    let matching_whitespace_len = line_bytes
13437                        .zip(comment_prefix_whitespace.bytes())
13438                        .take_while(|(a, b)| a == b)
13439                        .count() as u32;
13440                    let end = Point::new(
13441                        start.row,
13442                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13443                    );
13444                    start..end
13445                } else {
13446                    start..start
13447                }
13448            }
13449
13450            fn comment_suffix_range(
13451                snapshot: &MultiBufferSnapshot,
13452                row: MultiBufferRow,
13453                comment_suffix: &str,
13454                comment_suffix_has_leading_space: bool,
13455            ) -> Range<Point> {
13456                let end = Point::new(row.0, snapshot.line_len(row));
13457                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13458
13459                let mut line_end_bytes = snapshot
13460                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13461                    .flatten()
13462                    .copied();
13463
13464                let leading_space_len = if suffix_start_column > 0
13465                    && line_end_bytes.next() == Some(b' ')
13466                    && comment_suffix_has_leading_space
13467                {
13468                    1
13469                } else {
13470                    0
13471                };
13472
13473                // If this line currently begins with the line comment prefix, then record
13474                // the range containing the prefix.
13475                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13476                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13477                    start..end
13478                } else {
13479                    end..end
13480                }
13481            }
13482
13483            // TODO: Handle selections that cross excerpts
13484            for selection in &mut selections {
13485                let start_column = snapshot
13486                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13487                    .len;
13488                let language = if let Some(language) =
13489                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13490                {
13491                    language
13492                } else {
13493                    continue;
13494                };
13495
13496                selection_edit_ranges.clear();
13497
13498                // If multiple selections contain a given row, avoid processing that
13499                // row more than once.
13500                let mut start_row = MultiBufferRow(selection.start.row);
13501                if last_toggled_row == Some(start_row) {
13502                    start_row = start_row.next_row();
13503                }
13504                let end_row =
13505                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13506                        MultiBufferRow(selection.end.row - 1)
13507                    } else {
13508                        MultiBufferRow(selection.end.row)
13509                    };
13510                last_toggled_row = Some(end_row);
13511
13512                if start_row > end_row {
13513                    continue;
13514                }
13515
13516                // If the language has line comments, toggle those.
13517                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13518
13519                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13520                if ignore_indent {
13521                    full_comment_prefixes = full_comment_prefixes
13522                        .into_iter()
13523                        .map(|s| Arc::from(s.trim_end()))
13524                        .collect();
13525                }
13526
13527                if !full_comment_prefixes.is_empty() {
13528                    let first_prefix = full_comment_prefixes
13529                        .first()
13530                        .expect("prefixes is non-empty");
13531                    let prefix_trimmed_lengths = full_comment_prefixes
13532                        .iter()
13533                        .map(|p| p.trim_end_matches(' ').len())
13534                        .collect::<SmallVec<[usize; 4]>>();
13535
13536                    let mut all_selection_lines_are_comments = true;
13537
13538                    for row in start_row.0..=end_row.0 {
13539                        let row = MultiBufferRow(row);
13540                        if start_row < end_row && snapshot.is_line_blank(row) {
13541                            continue;
13542                        }
13543
13544                        let prefix_range = full_comment_prefixes
13545                            .iter()
13546                            .zip(prefix_trimmed_lengths.iter().copied())
13547                            .map(|(prefix, trimmed_prefix_len)| {
13548                                comment_prefix_range(
13549                                    snapshot.deref(),
13550                                    row,
13551                                    &prefix[..trimmed_prefix_len],
13552                                    &prefix[trimmed_prefix_len..],
13553                                    ignore_indent,
13554                                )
13555                            })
13556                            .max_by_key(|range| range.end.column - range.start.column)
13557                            .expect("prefixes is non-empty");
13558
13559                        if prefix_range.is_empty() {
13560                            all_selection_lines_are_comments = false;
13561                        }
13562
13563                        selection_edit_ranges.push(prefix_range);
13564                    }
13565
13566                    if all_selection_lines_are_comments {
13567                        edits.extend(
13568                            selection_edit_ranges
13569                                .iter()
13570                                .cloned()
13571                                .map(|range| (range, empty_str.clone())),
13572                        );
13573                    } else {
13574                        let min_column = selection_edit_ranges
13575                            .iter()
13576                            .map(|range| range.start.column)
13577                            .min()
13578                            .unwrap_or(0);
13579                        edits.extend(selection_edit_ranges.iter().map(|range| {
13580                            let position = Point::new(range.start.row, min_column);
13581                            (position..position, first_prefix.clone())
13582                        }));
13583                    }
13584                } else if let Some((full_comment_prefix, comment_suffix)) =
13585                    language.block_comment_delimiters()
13586                {
13587                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13588                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13589                    let prefix_range = comment_prefix_range(
13590                        snapshot.deref(),
13591                        start_row,
13592                        comment_prefix,
13593                        comment_prefix_whitespace,
13594                        ignore_indent,
13595                    );
13596                    let suffix_range = comment_suffix_range(
13597                        snapshot.deref(),
13598                        end_row,
13599                        comment_suffix.trim_start_matches(' '),
13600                        comment_suffix.starts_with(' '),
13601                    );
13602
13603                    if prefix_range.is_empty() || suffix_range.is_empty() {
13604                        edits.push((
13605                            prefix_range.start..prefix_range.start,
13606                            full_comment_prefix.clone(),
13607                        ));
13608                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13609                        suffixes_inserted.push((end_row, comment_suffix.len()));
13610                    } else {
13611                        edits.push((prefix_range, empty_str.clone()));
13612                        edits.push((suffix_range, empty_str.clone()));
13613                    }
13614                } else {
13615                    continue;
13616                }
13617            }
13618
13619            drop(snapshot);
13620            this.buffer.update(cx, |buffer, cx| {
13621                buffer.edit(edits, None, cx);
13622            });
13623
13624            // Adjust selections so that they end before any comment suffixes that
13625            // were inserted.
13626            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13627            let mut selections = this.selections.all::<Point>(cx);
13628            let snapshot = this.buffer.read(cx).read(cx);
13629            for selection in &mut selections {
13630                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13631                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13632                        Ordering::Less => {
13633                            suffixes_inserted.next();
13634                            continue;
13635                        }
13636                        Ordering::Greater => break,
13637                        Ordering::Equal => {
13638                            if selection.end.column == snapshot.line_len(row) {
13639                                if selection.is_empty() {
13640                                    selection.start.column -= suffix_len as u32;
13641                                }
13642                                selection.end.column -= suffix_len as u32;
13643                            }
13644                            break;
13645                        }
13646                    }
13647                }
13648            }
13649
13650            drop(snapshot);
13651            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13652                s.select(selections)
13653            });
13654
13655            let selections = this.selections.all::<Point>(cx);
13656            let selections_on_single_row = selections.windows(2).all(|selections| {
13657                selections[0].start.row == selections[1].start.row
13658                    && selections[0].end.row == selections[1].end.row
13659                    && selections[0].start.row == selections[0].end.row
13660            });
13661            let selections_selecting = selections
13662                .iter()
13663                .any(|selection| selection.start != selection.end);
13664            let advance_downwards = action.advance_downwards
13665                && selections_on_single_row
13666                && !selections_selecting
13667                && !matches!(this.mode, EditorMode::SingleLine { .. });
13668
13669            if advance_downwards {
13670                let snapshot = this.buffer.read(cx).snapshot(cx);
13671
13672                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13673                    s.move_cursors_with(|display_snapshot, display_point, _| {
13674                        let mut point = display_point.to_point(display_snapshot);
13675                        point.row += 1;
13676                        point = snapshot.clip_point(point, Bias::Left);
13677                        let display_point = point.to_display_point(display_snapshot);
13678                        let goal = SelectionGoal::HorizontalPosition(
13679                            display_snapshot
13680                                .x_for_display_point(display_point, text_layout_details)
13681                                .into(),
13682                        );
13683                        (display_point, goal)
13684                    })
13685                });
13686            }
13687        });
13688    }
13689
13690    pub fn select_enclosing_symbol(
13691        &mut self,
13692        _: &SelectEnclosingSymbol,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13697
13698        let buffer = self.buffer.read(cx).snapshot(cx);
13699        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13700
13701        fn update_selection(
13702            selection: &Selection<usize>,
13703            buffer_snap: &MultiBufferSnapshot,
13704        ) -> Option<Selection<usize>> {
13705            let cursor = selection.head();
13706            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13707            for symbol in symbols.iter().rev() {
13708                let start = symbol.range.start.to_offset(buffer_snap);
13709                let end = symbol.range.end.to_offset(buffer_snap);
13710                let new_range = start..end;
13711                if start < selection.start || end > selection.end {
13712                    return Some(Selection {
13713                        id: selection.id,
13714                        start: new_range.start,
13715                        end: new_range.end,
13716                        goal: SelectionGoal::None,
13717                        reversed: selection.reversed,
13718                    });
13719                }
13720            }
13721            None
13722        }
13723
13724        let mut selected_larger_symbol = false;
13725        let new_selections = old_selections
13726            .iter()
13727            .map(|selection| match update_selection(selection, &buffer) {
13728                Some(new_selection) => {
13729                    if new_selection.range() != selection.range() {
13730                        selected_larger_symbol = true;
13731                    }
13732                    new_selection
13733                }
13734                None => selection.clone(),
13735            })
13736            .collect::<Vec<_>>();
13737
13738        if selected_larger_symbol {
13739            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13740                s.select(new_selections);
13741            });
13742        }
13743    }
13744
13745    pub fn select_larger_syntax_node(
13746        &mut self,
13747        _: &SelectLargerSyntaxNode,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        let Some(visible_row_count) = self.visible_row_count() else {
13752            return;
13753        };
13754        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13755        if old_selections.is_empty() {
13756            return;
13757        }
13758
13759        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13760
13761        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13762        let buffer = self.buffer.read(cx).snapshot(cx);
13763
13764        let mut selected_larger_node = false;
13765        let mut new_selections = old_selections
13766            .iter()
13767            .map(|selection| {
13768                let old_range = selection.start..selection.end;
13769
13770                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13771                    // manually select word at selection
13772                    if ["string_content", "inline"].contains(&node.kind()) {
13773                        let word_range = {
13774                            let display_point = buffer
13775                                .offset_to_point(old_range.start)
13776                                .to_display_point(&display_map);
13777                            let Range { start, end } =
13778                                movement::surrounding_word(&display_map, display_point);
13779                            start.to_point(&display_map).to_offset(&buffer)
13780                                ..end.to_point(&display_map).to_offset(&buffer)
13781                        };
13782                        // ignore if word is already selected
13783                        if !word_range.is_empty() && old_range != word_range {
13784                            let last_word_range = {
13785                                let display_point = buffer
13786                                    .offset_to_point(old_range.end)
13787                                    .to_display_point(&display_map);
13788                                let Range { start, end } =
13789                                    movement::surrounding_word(&display_map, display_point);
13790                                start.to_point(&display_map).to_offset(&buffer)
13791                                    ..end.to_point(&display_map).to_offset(&buffer)
13792                            };
13793                            // only select word if start and end point belongs to same word
13794                            if word_range == last_word_range {
13795                                selected_larger_node = true;
13796                                return Selection {
13797                                    id: selection.id,
13798                                    start: word_range.start,
13799                                    end: word_range.end,
13800                                    goal: SelectionGoal::None,
13801                                    reversed: selection.reversed,
13802                                };
13803                            }
13804                        }
13805                    }
13806                }
13807
13808                let mut new_range = old_range.clone();
13809                while let Some((_node, containing_range)) =
13810                    buffer.syntax_ancestor(new_range.clone())
13811                {
13812                    new_range = match containing_range {
13813                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13814                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13815                    };
13816                    if !display_map.intersects_fold(new_range.start)
13817                        && !display_map.intersects_fold(new_range.end)
13818                    {
13819                        break;
13820                    }
13821                }
13822
13823                selected_larger_node |= new_range != old_range;
13824                Selection {
13825                    id: selection.id,
13826                    start: new_range.start,
13827                    end: new_range.end,
13828                    goal: SelectionGoal::None,
13829                    reversed: selection.reversed,
13830                }
13831            })
13832            .collect::<Vec<_>>();
13833
13834        if !selected_larger_node {
13835            return; // don't put this call in the history
13836        }
13837
13838        // scroll based on transformation done to the last selection created by the user
13839        let (last_old, last_new) = old_selections
13840            .last()
13841            .zip(new_selections.last().cloned())
13842            .expect("old_selections isn't empty");
13843
13844        // revert selection
13845        let is_selection_reversed = {
13846            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13847            new_selections.last_mut().expect("checked above").reversed =
13848                should_newest_selection_be_reversed;
13849            should_newest_selection_be_reversed
13850        };
13851
13852        if selected_larger_node {
13853            self.select_syntax_node_history.disable_clearing = true;
13854            self.change_selections(None, window, cx, |s| {
13855                s.select(new_selections.clone());
13856            });
13857            self.select_syntax_node_history.disable_clearing = false;
13858        }
13859
13860        let start_row = last_new.start.to_display_point(&display_map).row().0;
13861        let end_row = last_new.end.to_display_point(&display_map).row().0;
13862        let selection_height = end_row - start_row + 1;
13863        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13864
13865        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13866        let scroll_behavior = if fits_on_the_screen {
13867            self.request_autoscroll(Autoscroll::fit(), cx);
13868            SelectSyntaxNodeScrollBehavior::FitSelection
13869        } else if is_selection_reversed {
13870            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13871            SelectSyntaxNodeScrollBehavior::CursorTop
13872        } else {
13873            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13874            SelectSyntaxNodeScrollBehavior::CursorBottom
13875        };
13876
13877        self.select_syntax_node_history.push((
13878            old_selections,
13879            scroll_behavior,
13880            is_selection_reversed,
13881        ));
13882    }
13883
13884    pub fn select_smaller_syntax_node(
13885        &mut self,
13886        _: &SelectSmallerSyntaxNode,
13887        window: &mut Window,
13888        cx: &mut Context<Self>,
13889    ) {
13890        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13891
13892        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13893            self.select_syntax_node_history.pop()
13894        {
13895            if let Some(selection) = selections.last_mut() {
13896                selection.reversed = is_selection_reversed;
13897            }
13898
13899            self.select_syntax_node_history.disable_clearing = true;
13900            self.change_selections(None, window, cx, |s| {
13901                s.select(selections.to_vec());
13902            });
13903            self.select_syntax_node_history.disable_clearing = false;
13904
13905            match scroll_behavior {
13906                SelectSyntaxNodeScrollBehavior::CursorTop => {
13907                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13908                }
13909                SelectSyntaxNodeScrollBehavior::FitSelection => {
13910                    self.request_autoscroll(Autoscroll::fit(), cx);
13911                }
13912                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13913                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13914                }
13915            }
13916        }
13917    }
13918
13919    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13920        if !EditorSettings::get_global(cx).gutter.runnables {
13921            self.clear_tasks();
13922            return Task::ready(());
13923        }
13924        let project = self.project.as_ref().map(Entity::downgrade);
13925        let task_sources = self.lsp_task_sources(cx);
13926        let multi_buffer = self.buffer.downgrade();
13927        cx.spawn_in(window, async move |editor, cx| {
13928            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13929            let Some(project) = project.and_then(|p| p.upgrade()) else {
13930                return;
13931            };
13932            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13933                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13934            }) else {
13935                return;
13936            };
13937
13938            let hide_runnables = project
13939                .update(cx, |project, cx| {
13940                    // Do not display any test indicators in non-dev server remote projects.
13941                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13942                })
13943                .unwrap_or(true);
13944            if hide_runnables {
13945                return;
13946            }
13947            let new_rows =
13948                cx.background_spawn({
13949                    let snapshot = display_snapshot.clone();
13950                    async move {
13951                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13952                    }
13953                })
13954                    .await;
13955            let Ok(lsp_tasks) =
13956                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13957            else {
13958                return;
13959            };
13960            let lsp_tasks = lsp_tasks.await;
13961
13962            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13963                lsp_tasks
13964                    .into_iter()
13965                    .flat_map(|(kind, tasks)| {
13966                        tasks.into_iter().filter_map(move |(location, task)| {
13967                            Some((kind.clone(), location?, task))
13968                        })
13969                    })
13970                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13971                        let buffer = location.target.buffer;
13972                        let buffer_snapshot = buffer.read(cx).snapshot();
13973                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13974                            |(excerpt_id, snapshot, _)| {
13975                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13976                                    display_snapshot
13977                                        .buffer_snapshot
13978                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13979                                } else {
13980                                    None
13981                                }
13982                            },
13983                        );
13984                        if let Some(offset) = offset {
13985                            let task_buffer_range =
13986                                location.target.range.to_point(&buffer_snapshot);
13987                            let context_buffer_range =
13988                                task_buffer_range.to_offset(&buffer_snapshot);
13989                            let context_range = BufferOffset(context_buffer_range.start)
13990                                ..BufferOffset(context_buffer_range.end);
13991
13992                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13993                                .or_insert_with(|| RunnableTasks {
13994                                    templates: Vec::new(),
13995                                    offset,
13996                                    column: task_buffer_range.start.column,
13997                                    extra_variables: HashMap::default(),
13998                                    context_range,
13999                                })
14000                                .templates
14001                                .push((kind, task.original_task().clone()));
14002                        }
14003
14004                        acc
14005                    })
14006            }) else {
14007                return;
14008            };
14009
14010            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14011                buffer.language_settings(cx).tasks.prefer_lsp
14012            }) else {
14013                return;
14014            };
14015
14016            let rows = Self::runnable_rows(
14017                project,
14018                display_snapshot,
14019                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14020                new_rows,
14021                cx.clone(),
14022            );
14023            editor
14024                .update(cx, |editor, _| {
14025                    editor.clear_tasks();
14026                    for (key, mut value) in rows {
14027                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14028                            value.templates.extend(lsp_tasks.templates);
14029                        }
14030
14031                        editor.insert_tasks(key, value);
14032                    }
14033                    for (key, value) in lsp_tasks_by_rows {
14034                        editor.insert_tasks(key, value);
14035                    }
14036                })
14037                .ok();
14038        })
14039    }
14040    fn fetch_runnable_ranges(
14041        snapshot: &DisplaySnapshot,
14042        range: Range<Anchor>,
14043    ) -> Vec<language::RunnableRange> {
14044        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14045    }
14046
14047    fn runnable_rows(
14048        project: Entity<Project>,
14049        snapshot: DisplaySnapshot,
14050        prefer_lsp: bool,
14051        runnable_ranges: Vec<RunnableRange>,
14052        mut cx: AsyncWindowContext,
14053    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
14054        runnable_ranges
14055            .into_iter()
14056            .filter_map(|mut runnable| {
14057                let mut tasks = cx
14058                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14059                    .ok()?;
14060                if prefer_lsp {
14061                    tasks.retain(|(task_kind, _)| {
14062                        !matches!(task_kind, TaskSourceKind::Language { .. })
14063                    });
14064                }
14065                if tasks.is_empty() {
14066                    return None;
14067                }
14068
14069                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14070
14071                let row = snapshot
14072                    .buffer_snapshot
14073                    .buffer_line_for_row(MultiBufferRow(point.row))?
14074                    .1
14075                    .start
14076                    .row;
14077
14078                let context_range =
14079                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14080                Some((
14081                    (runnable.buffer_id, row),
14082                    RunnableTasks {
14083                        templates: tasks,
14084                        offset: snapshot
14085                            .buffer_snapshot
14086                            .anchor_before(runnable.run_range.start),
14087                        context_range,
14088                        column: point.column,
14089                        extra_variables: runnable.extra_captures,
14090                    },
14091                ))
14092            })
14093            .collect()
14094    }
14095
14096    fn templates_with_tags(
14097        project: &Entity<Project>,
14098        runnable: &mut Runnable,
14099        cx: &mut App,
14100    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
14101        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14102            let (worktree_id, file) = project
14103                .buffer_for_id(runnable.buffer, cx)
14104                .and_then(|buffer| buffer.read(cx).file())
14105                .map(|file| (file.worktree_id(cx), file.clone()))
14106                .unzip();
14107
14108            (
14109                project.task_store().read(cx).task_inventory().cloned(),
14110                worktree_id,
14111                file,
14112            )
14113        });
14114
14115        let mut templates_with_tags = mem::take(&mut runnable.tags)
14116            .into_iter()
14117            .flat_map(|RunnableTag(tag)| {
14118                inventory
14119                    .as_ref()
14120                    .into_iter()
14121                    .flat_map(|inventory| {
14122                        inventory.read(cx).list_tasks(
14123                            file.clone(),
14124                            Some(runnable.language.clone()),
14125                            worktree_id,
14126                            cx,
14127                        )
14128                    })
14129                    .filter(move |(_, template)| {
14130                        template.tags.iter().any(|source_tag| source_tag == &tag)
14131                    })
14132            })
14133            .sorted_by_key(|(kind, _)| kind.to_owned())
14134            .collect::<Vec<_>>();
14135        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14136            // Strongest source wins; if we have worktree tag binding, prefer that to
14137            // global and language bindings;
14138            // if we have a global binding, prefer that to language binding.
14139            let first_mismatch = templates_with_tags
14140                .iter()
14141                .position(|(tag_source, _)| tag_source != leading_tag_source);
14142            if let Some(index) = first_mismatch {
14143                templates_with_tags.truncate(index);
14144            }
14145        }
14146
14147        templates_with_tags
14148    }
14149
14150    pub fn move_to_enclosing_bracket(
14151        &mut self,
14152        _: &MoveToEnclosingBracket,
14153        window: &mut Window,
14154        cx: &mut Context<Self>,
14155    ) {
14156        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14157        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14158            s.move_offsets_with(|snapshot, selection| {
14159                let Some(enclosing_bracket_ranges) =
14160                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14161                else {
14162                    return;
14163                };
14164
14165                let mut best_length = usize::MAX;
14166                let mut best_inside = false;
14167                let mut best_in_bracket_range = false;
14168                let mut best_destination = None;
14169                for (open, close) in enclosing_bracket_ranges {
14170                    let close = close.to_inclusive();
14171                    let length = close.end() - open.start;
14172                    let inside = selection.start >= open.end && selection.end <= *close.start();
14173                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14174                        || close.contains(&selection.head());
14175
14176                    // If best is next to a bracket and current isn't, skip
14177                    if !in_bracket_range && best_in_bracket_range {
14178                        continue;
14179                    }
14180
14181                    // Prefer smaller lengths unless best is inside and current isn't
14182                    if length > best_length && (best_inside || !inside) {
14183                        continue;
14184                    }
14185
14186                    best_length = length;
14187                    best_inside = inside;
14188                    best_in_bracket_range = in_bracket_range;
14189                    best_destination = Some(
14190                        if close.contains(&selection.start) && close.contains(&selection.end) {
14191                            if inside { open.end } else { open.start }
14192                        } else if inside {
14193                            *close.start()
14194                        } else {
14195                            *close.end()
14196                        },
14197                    );
14198                }
14199
14200                if let Some(destination) = best_destination {
14201                    selection.collapse_to(destination, SelectionGoal::None);
14202                }
14203            })
14204        });
14205    }
14206
14207    pub fn undo_selection(
14208        &mut self,
14209        _: &UndoSelection,
14210        window: &mut Window,
14211        cx: &mut Context<Self>,
14212    ) {
14213        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14214        self.end_selection(window, cx);
14215        self.selection_history.mode = SelectionHistoryMode::Undoing;
14216        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14217            self.change_selections(None, window, cx, |s| {
14218                s.select_anchors(entry.selections.to_vec())
14219            });
14220            self.select_next_state = entry.select_next_state;
14221            self.select_prev_state = entry.select_prev_state;
14222            self.add_selections_state = entry.add_selections_state;
14223            self.request_autoscroll(Autoscroll::newest(), cx);
14224        }
14225        self.selection_history.mode = SelectionHistoryMode::Normal;
14226    }
14227
14228    pub fn redo_selection(
14229        &mut self,
14230        _: &RedoSelection,
14231        window: &mut Window,
14232        cx: &mut Context<Self>,
14233    ) {
14234        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14235        self.end_selection(window, cx);
14236        self.selection_history.mode = SelectionHistoryMode::Redoing;
14237        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14238            self.change_selections(None, window, cx, |s| {
14239                s.select_anchors(entry.selections.to_vec())
14240            });
14241            self.select_next_state = entry.select_next_state;
14242            self.select_prev_state = entry.select_prev_state;
14243            self.add_selections_state = entry.add_selections_state;
14244            self.request_autoscroll(Autoscroll::newest(), cx);
14245        }
14246        self.selection_history.mode = SelectionHistoryMode::Normal;
14247    }
14248
14249    pub fn expand_excerpts(
14250        &mut self,
14251        action: &ExpandExcerpts,
14252        _: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14256    }
14257
14258    pub fn expand_excerpts_down(
14259        &mut self,
14260        action: &ExpandExcerptsDown,
14261        _: &mut Window,
14262        cx: &mut Context<Self>,
14263    ) {
14264        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14265    }
14266
14267    pub fn expand_excerpts_up(
14268        &mut self,
14269        action: &ExpandExcerptsUp,
14270        _: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) {
14273        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14274    }
14275
14276    pub fn expand_excerpts_for_direction(
14277        &mut self,
14278        lines: u32,
14279        direction: ExpandExcerptDirection,
14280
14281        cx: &mut Context<Self>,
14282    ) {
14283        let selections = self.selections.disjoint_anchors();
14284
14285        let lines = if lines == 0 {
14286            EditorSettings::get_global(cx).expand_excerpt_lines
14287        } else {
14288            lines
14289        };
14290
14291        self.buffer.update(cx, |buffer, cx| {
14292            let snapshot = buffer.snapshot(cx);
14293            let mut excerpt_ids = selections
14294                .iter()
14295                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14296                .collect::<Vec<_>>();
14297            excerpt_ids.sort();
14298            excerpt_ids.dedup();
14299            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14300        })
14301    }
14302
14303    pub fn expand_excerpt(
14304        &mut self,
14305        excerpt: ExcerptId,
14306        direction: ExpandExcerptDirection,
14307        window: &mut Window,
14308        cx: &mut Context<Self>,
14309    ) {
14310        let current_scroll_position = self.scroll_position(cx);
14311        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14312        let mut should_scroll_up = false;
14313
14314        if direction == ExpandExcerptDirection::Down {
14315            let multi_buffer = self.buffer.read(cx);
14316            let snapshot = multi_buffer.snapshot(cx);
14317            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14318                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14319                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14320                        let buffer_snapshot = buffer.read(cx).snapshot();
14321                        let excerpt_end_row =
14322                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14323                        let last_row = buffer_snapshot.max_point().row;
14324                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14325                        should_scroll_up = lines_below >= lines_to_expand;
14326                    }
14327                }
14328            }
14329        }
14330
14331        self.buffer.update(cx, |buffer, cx| {
14332            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14333        });
14334
14335        if should_scroll_up {
14336            let new_scroll_position =
14337                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14338            self.set_scroll_position(new_scroll_position, window, cx);
14339        }
14340    }
14341
14342    pub fn go_to_singleton_buffer_point(
14343        &mut self,
14344        point: Point,
14345        window: &mut Window,
14346        cx: &mut Context<Self>,
14347    ) {
14348        self.go_to_singleton_buffer_range(point..point, window, cx);
14349    }
14350
14351    pub fn go_to_singleton_buffer_range(
14352        &mut self,
14353        range: Range<Point>,
14354        window: &mut Window,
14355        cx: &mut Context<Self>,
14356    ) {
14357        let multibuffer = self.buffer().read(cx);
14358        let Some(buffer) = multibuffer.as_singleton() else {
14359            return;
14360        };
14361        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14362            return;
14363        };
14364        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14365            return;
14366        };
14367        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14368            s.select_anchor_ranges([start..end])
14369        });
14370    }
14371
14372    pub fn go_to_diagnostic(
14373        &mut self,
14374        _: &GoToDiagnostic,
14375        window: &mut Window,
14376        cx: &mut Context<Self>,
14377    ) {
14378        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14379        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14380    }
14381
14382    pub fn go_to_prev_diagnostic(
14383        &mut self,
14384        _: &GoToPreviousDiagnostic,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14389        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14390    }
14391
14392    pub fn go_to_diagnostic_impl(
14393        &mut self,
14394        direction: Direction,
14395        window: &mut Window,
14396        cx: &mut Context<Self>,
14397    ) {
14398        let buffer = self.buffer.read(cx).snapshot(cx);
14399        let selection = self.selections.newest::<usize>(cx);
14400
14401        let mut active_group_id = None;
14402        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14403            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14404                active_group_id = Some(active_group.group_id);
14405            }
14406        }
14407
14408        fn filtered(
14409            snapshot: EditorSnapshot,
14410            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14411        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14412            diagnostics
14413                .filter(|entry| entry.range.start != entry.range.end)
14414                .filter(|entry| !entry.diagnostic.is_unnecessary)
14415                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14416        }
14417
14418        let snapshot = self.snapshot(window, cx);
14419        let before = filtered(
14420            snapshot.clone(),
14421            buffer
14422                .diagnostics_in_range(0..selection.start)
14423                .filter(|entry| entry.range.start <= selection.start),
14424        );
14425        let after = filtered(
14426            snapshot,
14427            buffer
14428                .diagnostics_in_range(selection.start..buffer.len())
14429                .filter(|entry| entry.range.start >= selection.start),
14430        );
14431
14432        let mut found: Option<DiagnosticEntry<usize>> = None;
14433        if direction == Direction::Prev {
14434            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14435            {
14436                for diagnostic in prev_diagnostics.into_iter().rev() {
14437                    if diagnostic.range.start != selection.start
14438                        || active_group_id
14439                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14440                    {
14441                        found = Some(diagnostic);
14442                        break 'outer;
14443                    }
14444                }
14445            }
14446        } else {
14447            for diagnostic in after.chain(before) {
14448                if diagnostic.range.start != selection.start
14449                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14450                {
14451                    found = Some(diagnostic);
14452                    break;
14453                }
14454            }
14455        }
14456        let Some(next_diagnostic) = found else {
14457            return;
14458        };
14459
14460        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14461            return;
14462        };
14463        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14464            s.select_ranges(vec![
14465                next_diagnostic.range.start..next_diagnostic.range.start,
14466            ])
14467        });
14468        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14469        self.refresh_inline_completion(false, true, window, cx);
14470    }
14471
14472    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14474        let snapshot = self.snapshot(window, cx);
14475        let selection = self.selections.newest::<Point>(cx);
14476        self.go_to_hunk_before_or_after_position(
14477            &snapshot,
14478            selection.head(),
14479            Direction::Next,
14480            window,
14481            cx,
14482        );
14483    }
14484
14485    pub fn go_to_hunk_before_or_after_position(
14486        &mut self,
14487        snapshot: &EditorSnapshot,
14488        position: Point,
14489        direction: Direction,
14490        window: &mut Window,
14491        cx: &mut Context<Editor>,
14492    ) {
14493        let row = if direction == Direction::Next {
14494            self.hunk_after_position(snapshot, position)
14495                .map(|hunk| hunk.row_range.start)
14496        } else {
14497            self.hunk_before_position(snapshot, position)
14498        };
14499
14500        if let Some(row) = row {
14501            let destination = Point::new(row.0, 0);
14502            let autoscroll = Autoscroll::center();
14503
14504            self.unfold_ranges(&[destination..destination], false, false, cx);
14505            self.change_selections(Some(autoscroll), window, cx, |s| {
14506                s.select_ranges([destination..destination]);
14507            });
14508        }
14509    }
14510
14511    fn hunk_after_position(
14512        &mut self,
14513        snapshot: &EditorSnapshot,
14514        position: Point,
14515    ) -> Option<MultiBufferDiffHunk> {
14516        snapshot
14517            .buffer_snapshot
14518            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14519            .find(|hunk| hunk.row_range.start.0 > position.row)
14520            .or_else(|| {
14521                snapshot
14522                    .buffer_snapshot
14523                    .diff_hunks_in_range(Point::zero()..position)
14524                    .find(|hunk| hunk.row_range.end.0 < position.row)
14525            })
14526    }
14527
14528    fn go_to_prev_hunk(
14529        &mut self,
14530        _: &GoToPreviousHunk,
14531        window: &mut Window,
14532        cx: &mut Context<Self>,
14533    ) {
14534        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14535        let snapshot = self.snapshot(window, cx);
14536        let selection = self.selections.newest::<Point>(cx);
14537        self.go_to_hunk_before_or_after_position(
14538            &snapshot,
14539            selection.head(),
14540            Direction::Prev,
14541            window,
14542            cx,
14543        );
14544    }
14545
14546    fn hunk_before_position(
14547        &mut self,
14548        snapshot: &EditorSnapshot,
14549        position: Point,
14550    ) -> Option<MultiBufferRow> {
14551        snapshot
14552            .buffer_snapshot
14553            .diff_hunk_before(position)
14554            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14555    }
14556
14557    fn go_to_next_change(
14558        &mut self,
14559        _: &GoToNextChange,
14560        window: &mut Window,
14561        cx: &mut Context<Self>,
14562    ) {
14563        if let Some(selections) = self
14564            .change_list
14565            .next_change(1, Direction::Next)
14566            .map(|s| s.to_vec())
14567        {
14568            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14569                let map = s.display_map();
14570                s.select_display_ranges(selections.iter().map(|a| {
14571                    let point = a.to_display_point(&map);
14572                    point..point
14573                }))
14574            })
14575        }
14576    }
14577
14578    fn go_to_previous_change(
14579        &mut self,
14580        _: &GoToPreviousChange,
14581        window: &mut Window,
14582        cx: &mut Context<Self>,
14583    ) {
14584        if let Some(selections) = self
14585            .change_list
14586            .next_change(1, Direction::Prev)
14587            .map(|s| s.to_vec())
14588        {
14589            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14590                let map = s.display_map();
14591                s.select_display_ranges(selections.iter().map(|a| {
14592                    let point = a.to_display_point(&map);
14593                    point..point
14594                }))
14595            })
14596        }
14597    }
14598
14599    fn go_to_line<T: 'static>(
14600        &mut self,
14601        position: Anchor,
14602        highlight_color: Option<Hsla>,
14603        window: &mut Window,
14604        cx: &mut Context<Self>,
14605    ) {
14606        let snapshot = self.snapshot(window, cx).display_snapshot;
14607        let position = position.to_point(&snapshot.buffer_snapshot);
14608        let start = snapshot
14609            .buffer_snapshot
14610            .clip_point(Point::new(position.row, 0), Bias::Left);
14611        let end = start + Point::new(1, 0);
14612        let start = snapshot.buffer_snapshot.anchor_before(start);
14613        let end = snapshot.buffer_snapshot.anchor_before(end);
14614
14615        self.highlight_rows::<T>(
14616            start..end,
14617            highlight_color
14618                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14619            Default::default(),
14620            cx,
14621        );
14622
14623        if self.buffer.read(cx).is_singleton() {
14624            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14625        }
14626    }
14627
14628    pub fn go_to_definition(
14629        &mut self,
14630        _: &GoToDefinition,
14631        window: &mut Window,
14632        cx: &mut Context<Self>,
14633    ) -> Task<Result<Navigated>> {
14634        let definition =
14635            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14636        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14637        cx.spawn_in(window, async move |editor, cx| {
14638            if definition.await? == Navigated::Yes {
14639                return Ok(Navigated::Yes);
14640            }
14641            match fallback_strategy {
14642                GoToDefinitionFallback::None => Ok(Navigated::No),
14643                GoToDefinitionFallback::FindAllReferences => {
14644                    match editor.update_in(cx, |editor, window, cx| {
14645                        editor.find_all_references(&FindAllReferences, window, cx)
14646                    })? {
14647                        Some(references) => references.await,
14648                        None => Ok(Navigated::No),
14649                    }
14650                }
14651            }
14652        })
14653    }
14654
14655    pub fn go_to_declaration(
14656        &mut self,
14657        _: &GoToDeclaration,
14658        window: &mut Window,
14659        cx: &mut Context<Self>,
14660    ) -> Task<Result<Navigated>> {
14661        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14662    }
14663
14664    pub fn go_to_declaration_split(
14665        &mut self,
14666        _: &GoToDeclaration,
14667        window: &mut Window,
14668        cx: &mut Context<Self>,
14669    ) -> Task<Result<Navigated>> {
14670        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14671    }
14672
14673    pub fn go_to_implementation(
14674        &mut self,
14675        _: &GoToImplementation,
14676        window: &mut Window,
14677        cx: &mut Context<Self>,
14678    ) -> Task<Result<Navigated>> {
14679        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14680    }
14681
14682    pub fn go_to_implementation_split(
14683        &mut self,
14684        _: &GoToImplementationSplit,
14685        window: &mut Window,
14686        cx: &mut Context<Self>,
14687    ) -> Task<Result<Navigated>> {
14688        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14689    }
14690
14691    pub fn go_to_type_definition(
14692        &mut self,
14693        _: &GoToTypeDefinition,
14694        window: &mut Window,
14695        cx: &mut Context<Self>,
14696    ) -> Task<Result<Navigated>> {
14697        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14698    }
14699
14700    pub fn go_to_definition_split(
14701        &mut self,
14702        _: &GoToDefinitionSplit,
14703        window: &mut Window,
14704        cx: &mut Context<Self>,
14705    ) -> Task<Result<Navigated>> {
14706        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14707    }
14708
14709    pub fn go_to_type_definition_split(
14710        &mut self,
14711        _: &GoToTypeDefinitionSplit,
14712        window: &mut Window,
14713        cx: &mut Context<Self>,
14714    ) -> Task<Result<Navigated>> {
14715        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14716    }
14717
14718    fn go_to_definition_of_kind(
14719        &mut self,
14720        kind: GotoDefinitionKind,
14721        split: bool,
14722        window: &mut Window,
14723        cx: &mut Context<Self>,
14724    ) -> Task<Result<Navigated>> {
14725        let Some(provider) = self.semantics_provider.clone() else {
14726            return Task::ready(Ok(Navigated::No));
14727        };
14728        let head = self.selections.newest::<usize>(cx).head();
14729        let buffer = self.buffer.read(cx);
14730        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14731            text_anchor
14732        } else {
14733            return Task::ready(Ok(Navigated::No));
14734        };
14735
14736        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14737            return Task::ready(Ok(Navigated::No));
14738        };
14739
14740        cx.spawn_in(window, async move |editor, cx| {
14741            let definitions = definitions.await?;
14742            let navigated = editor
14743                .update_in(cx, |editor, window, cx| {
14744                    editor.navigate_to_hover_links(
14745                        Some(kind),
14746                        definitions
14747                            .into_iter()
14748                            .filter(|location| {
14749                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14750                            })
14751                            .map(HoverLink::Text)
14752                            .collect::<Vec<_>>(),
14753                        split,
14754                        window,
14755                        cx,
14756                    )
14757                })?
14758                .await?;
14759            anyhow::Ok(navigated)
14760        })
14761    }
14762
14763    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14764        let selection = self.selections.newest_anchor();
14765        let head = selection.head();
14766        let tail = selection.tail();
14767
14768        let Some((buffer, start_position)) =
14769            self.buffer.read(cx).text_anchor_for_position(head, cx)
14770        else {
14771            return;
14772        };
14773
14774        let end_position = if head != tail {
14775            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14776                return;
14777            };
14778            Some(pos)
14779        } else {
14780            None
14781        };
14782
14783        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14784            let url = if let Some(end_pos) = end_position {
14785                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14786            } else {
14787                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14788            };
14789
14790            if let Some(url) = url {
14791                editor.update(cx, |_, cx| {
14792                    cx.open_url(&url);
14793                })
14794            } else {
14795                Ok(())
14796            }
14797        });
14798
14799        url_finder.detach();
14800    }
14801
14802    pub fn open_selected_filename(
14803        &mut self,
14804        _: &OpenSelectedFilename,
14805        window: &mut Window,
14806        cx: &mut Context<Self>,
14807    ) {
14808        let Some(workspace) = self.workspace() else {
14809            return;
14810        };
14811
14812        let position = self.selections.newest_anchor().head();
14813
14814        let Some((buffer, buffer_position)) =
14815            self.buffer.read(cx).text_anchor_for_position(position, cx)
14816        else {
14817            return;
14818        };
14819
14820        let project = self.project.clone();
14821
14822        cx.spawn_in(window, async move |_, cx| {
14823            let result = find_file(&buffer, project, buffer_position, cx).await;
14824
14825            if let Some((_, path)) = result {
14826                workspace
14827                    .update_in(cx, |workspace, window, cx| {
14828                        workspace.open_resolved_path(path, window, cx)
14829                    })?
14830                    .await?;
14831            }
14832            anyhow::Ok(())
14833        })
14834        .detach();
14835    }
14836
14837    pub(crate) fn navigate_to_hover_links(
14838        &mut self,
14839        kind: Option<GotoDefinitionKind>,
14840        mut definitions: Vec<HoverLink>,
14841        split: bool,
14842        window: &mut Window,
14843        cx: &mut Context<Editor>,
14844    ) -> Task<Result<Navigated>> {
14845        // If there is one definition, just open it directly
14846        if definitions.len() == 1 {
14847            let definition = definitions.pop().unwrap();
14848
14849            enum TargetTaskResult {
14850                Location(Option<Location>),
14851                AlreadyNavigated,
14852            }
14853
14854            let target_task = match definition {
14855                HoverLink::Text(link) => {
14856                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14857                }
14858                HoverLink::InlayHint(lsp_location, server_id) => {
14859                    let computation =
14860                        self.compute_target_location(lsp_location, server_id, window, cx);
14861                    cx.background_spawn(async move {
14862                        let location = computation.await?;
14863                        Ok(TargetTaskResult::Location(location))
14864                    })
14865                }
14866                HoverLink::Url(url) => {
14867                    cx.open_url(&url);
14868                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14869                }
14870                HoverLink::File(path) => {
14871                    if let Some(workspace) = self.workspace() {
14872                        cx.spawn_in(window, async move |_, cx| {
14873                            workspace
14874                                .update_in(cx, |workspace, window, cx| {
14875                                    workspace.open_resolved_path(path, window, cx)
14876                                })?
14877                                .await
14878                                .map(|_| TargetTaskResult::AlreadyNavigated)
14879                        })
14880                    } else {
14881                        Task::ready(Ok(TargetTaskResult::Location(None)))
14882                    }
14883                }
14884            };
14885            cx.spawn_in(window, async move |editor, cx| {
14886                let target = match target_task.await.context("target resolution task")? {
14887                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14888                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14889                    TargetTaskResult::Location(Some(target)) => target,
14890                };
14891
14892                editor.update_in(cx, |editor, window, cx| {
14893                    let Some(workspace) = editor.workspace() else {
14894                        return Navigated::No;
14895                    };
14896                    let pane = workspace.read(cx).active_pane().clone();
14897
14898                    let range = target.range.to_point(target.buffer.read(cx));
14899                    let range = editor.range_for_match(&range);
14900                    let range = collapse_multiline_range(range);
14901
14902                    if !split
14903                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14904                    {
14905                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14906                    } else {
14907                        window.defer(cx, move |window, cx| {
14908                            let target_editor: Entity<Self> =
14909                                workspace.update(cx, |workspace, cx| {
14910                                    let pane = if split {
14911                                        workspace.adjacent_pane(window, cx)
14912                                    } else {
14913                                        workspace.active_pane().clone()
14914                                    };
14915
14916                                    workspace.open_project_item(
14917                                        pane,
14918                                        target.buffer.clone(),
14919                                        true,
14920                                        true,
14921                                        window,
14922                                        cx,
14923                                    )
14924                                });
14925                            target_editor.update(cx, |target_editor, cx| {
14926                                // When selecting a definition in a different buffer, disable the nav history
14927                                // to avoid creating a history entry at the previous cursor location.
14928                                pane.update(cx, |pane, _| pane.disable_history());
14929                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14930                                pane.update(cx, |pane, _| pane.enable_history());
14931                            });
14932                        });
14933                    }
14934                    Navigated::Yes
14935                })
14936            })
14937        } else if !definitions.is_empty() {
14938            cx.spawn_in(window, async move |editor, cx| {
14939                let (title, location_tasks, workspace) = editor
14940                    .update_in(cx, |editor, window, cx| {
14941                        let tab_kind = match kind {
14942                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14943                            _ => "Definitions",
14944                        };
14945                        let title = definitions
14946                            .iter()
14947                            .find_map(|definition| match definition {
14948                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14949                                    let buffer = origin.buffer.read(cx);
14950                                    format!(
14951                                        "{} for {}",
14952                                        tab_kind,
14953                                        buffer
14954                                            .text_for_range(origin.range.clone())
14955                                            .collect::<String>()
14956                                    )
14957                                }),
14958                                HoverLink::InlayHint(_, _) => None,
14959                                HoverLink::Url(_) => None,
14960                                HoverLink::File(_) => None,
14961                            })
14962                            .unwrap_or(tab_kind.to_string());
14963                        let location_tasks = definitions
14964                            .into_iter()
14965                            .map(|definition| match definition {
14966                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14967                                HoverLink::InlayHint(lsp_location, server_id) => editor
14968                                    .compute_target_location(lsp_location, server_id, window, cx),
14969                                HoverLink::Url(_) => Task::ready(Ok(None)),
14970                                HoverLink::File(_) => Task::ready(Ok(None)),
14971                            })
14972                            .collect::<Vec<_>>();
14973                        (title, location_tasks, editor.workspace().clone())
14974                    })
14975                    .context("location tasks preparation")?;
14976
14977                let locations = future::join_all(location_tasks)
14978                    .await
14979                    .into_iter()
14980                    .filter_map(|location| location.transpose())
14981                    .collect::<Result<_>>()
14982                    .context("location tasks")?;
14983
14984                let Some(workspace) = workspace else {
14985                    return Ok(Navigated::No);
14986                };
14987                let opened = workspace
14988                    .update_in(cx, |workspace, window, cx| {
14989                        Self::open_locations_in_multibuffer(
14990                            workspace,
14991                            locations,
14992                            title,
14993                            split,
14994                            MultibufferSelectionMode::First,
14995                            window,
14996                            cx,
14997                        )
14998                    })
14999                    .ok();
15000
15001                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15002            })
15003        } else {
15004            Task::ready(Ok(Navigated::No))
15005        }
15006    }
15007
15008    fn compute_target_location(
15009        &self,
15010        lsp_location: lsp::Location,
15011        server_id: LanguageServerId,
15012        window: &mut Window,
15013        cx: &mut Context<Self>,
15014    ) -> Task<anyhow::Result<Option<Location>>> {
15015        let Some(project) = self.project.clone() else {
15016            return Task::ready(Ok(None));
15017        };
15018
15019        cx.spawn_in(window, async move |editor, cx| {
15020            let location_task = editor.update(cx, |_, cx| {
15021                project.update(cx, |project, cx| {
15022                    let language_server_name = project
15023                        .language_server_statuses(cx)
15024                        .find(|(id, _)| server_id == *id)
15025                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15026                    language_server_name.map(|language_server_name| {
15027                        project.open_local_buffer_via_lsp(
15028                            lsp_location.uri.clone(),
15029                            server_id,
15030                            language_server_name,
15031                            cx,
15032                        )
15033                    })
15034                })
15035            })?;
15036            let location = match location_task {
15037                Some(task) => Some({
15038                    let target_buffer_handle = task.await.context("open local buffer")?;
15039                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15040                        let target_start = target_buffer
15041                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15042                        let target_end = target_buffer
15043                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15044                        target_buffer.anchor_after(target_start)
15045                            ..target_buffer.anchor_before(target_end)
15046                    })?;
15047                    Location {
15048                        buffer: target_buffer_handle,
15049                        range,
15050                    }
15051                }),
15052                None => None,
15053            };
15054            Ok(location)
15055        })
15056    }
15057
15058    pub fn find_all_references(
15059        &mut self,
15060        _: &FindAllReferences,
15061        window: &mut Window,
15062        cx: &mut Context<Self>,
15063    ) -> Option<Task<Result<Navigated>>> {
15064        let selection = self.selections.newest::<usize>(cx);
15065        let multi_buffer = self.buffer.read(cx);
15066        let head = selection.head();
15067
15068        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15069        let head_anchor = multi_buffer_snapshot.anchor_at(
15070            head,
15071            if head < selection.tail() {
15072                Bias::Right
15073            } else {
15074                Bias::Left
15075            },
15076        );
15077
15078        match self
15079            .find_all_references_task_sources
15080            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15081        {
15082            Ok(_) => {
15083                log::info!(
15084                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15085                );
15086                return None;
15087            }
15088            Err(i) => {
15089                self.find_all_references_task_sources.insert(i, head_anchor);
15090            }
15091        }
15092
15093        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15094        let workspace = self.workspace()?;
15095        let project = workspace.read(cx).project().clone();
15096        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15097        Some(cx.spawn_in(window, async move |editor, cx| {
15098            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15099                if let Ok(i) = editor
15100                    .find_all_references_task_sources
15101                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15102                {
15103                    editor.find_all_references_task_sources.remove(i);
15104                }
15105            });
15106
15107            let locations = references.await?;
15108            if locations.is_empty() {
15109                return anyhow::Ok(Navigated::No);
15110            }
15111
15112            workspace.update_in(cx, |workspace, window, cx| {
15113                let title = locations
15114                    .first()
15115                    .as_ref()
15116                    .map(|location| {
15117                        let buffer = location.buffer.read(cx);
15118                        format!(
15119                            "References to `{}`",
15120                            buffer
15121                                .text_for_range(location.range.clone())
15122                                .collect::<String>()
15123                        )
15124                    })
15125                    .unwrap();
15126                Self::open_locations_in_multibuffer(
15127                    workspace,
15128                    locations,
15129                    title,
15130                    false,
15131                    MultibufferSelectionMode::First,
15132                    window,
15133                    cx,
15134                );
15135                Navigated::Yes
15136            })
15137        }))
15138    }
15139
15140    /// Opens a multibuffer with the given project locations in it
15141    pub fn open_locations_in_multibuffer(
15142        workspace: &mut Workspace,
15143        mut locations: Vec<Location>,
15144        title: String,
15145        split: bool,
15146        multibuffer_selection_mode: MultibufferSelectionMode,
15147        window: &mut Window,
15148        cx: &mut Context<Workspace>,
15149    ) {
15150        // If there are multiple definitions, open them in a multibuffer
15151        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15152        let mut locations = locations.into_iter().peekable();
15153        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15154        let capability = workspace.project().read(cx).capability();
15155
15156        let excerpt_buffer = cx.new(|cx| {
15157            let mut multibuffer = MultiBuffer::new(capability);
15158            while let Some(location) = locations.next() {
15159                let buffer = location.buffer.read(cx);
15160                let mut ranges_for_buffer = Vec::new();
15161                let range = location.range.to_point(buffer);
15162                ranges_for_buffer.push(range.clone());
15163
15164                while let Some(next_location) = locations.peek() {
15165                    if next_location.buffer == location.buffer {
15166                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15167                        locations.next();
15168                    } else {
15169                        break;
15170                    }
15171                }
15172
15173                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15174                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15175                    PathKey::for_buffer(&location.buffer, cx),
15176                    location.buffer.clone(),
15177                    ranges_for_buffer,
15178                    DEFAULT_MULTIBUFFER_CONTEXT,
15179                    cx,
15180                );
15181                ranges.extend(new_ranges)
15182            }
15183
15184            multibuffer.with_title(title)
15185        });
15186
15187        let editor = cx.new(|cx| {
15188            Editor::for_multibuffer(
15189                excerpt_buffer,
15190                Some(workspace.project().clone()),
15191                window,
15192                cx,
15193            )
15194        });
15195        editor.update(cx, |editor, cx| {
15196            match multibuffer_selection_mode {
15197                MultibufferSelectionMode::First => {
15198                    if let Some(first_range) = ranges.first() {
15199                        editor.change_selections(None, window, cx, |selections| {
15200                            selections.clear_disjoint();
15201                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15202                        });
15203                    }
15204                    editor.highlight_background::<Self>(
15205                        &ranges,
15206                        |theme| theme.editor_highlighted_line_background,
15207                        cx,
15208                    );
15209                }
15210                MultibufferSelectionMode::All => {
15211                    editor.change_selections(None, window, cx, |selections| {
15212                        selections.clear_disjoint();
15213                        selections.select_anchor_ranges(ranges);
15214                    });
15215                }
15216            }
15217            editor.register_buffers_with_language_servers(cx);
15218        });
15219
15220        let item = Box::new(editor);
15221        let item_id = item.item_id();
15222
15223        if split {
15224            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15225        } else {
15226            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15227                let (preview_item_id, preview_item_idx) =
15228                    workspace.active_pane().read_with(cx, |pane, _| {
15229                        (pane.preview_item_id(), pane.preview_item_idx())
15230                    });
15231
15232                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15233
15234                if let Some(preview_item_id) = preview_item_id {
15235                    workspace.active_pane().update(cx, |pane, cx| {
15236                        pane.remove_item(preview_item_id, false, false, window, cx);
15237                    });
15238                }
15239            } else {
15240                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15241            }
15242        }
15243        workspace.active_pane().update(cx, |pane, cx| {
15244            pane.set_preview_item_id(Some(item_id), cx);
15245        });
15246    }
15247
15248    pub fn rename(
15249        &mut self,
15250        _: &Rename,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) -> Option<Task<Result<()>>> {
15254        use language::ToOffset as _;
15255
15256        let provider = self.semantics_provider.clone()?;
15257        let selection = self.selections.newest_anchor().clone();
15258        let (cursor_buffer, cursor_buffer_position) = self
15259            .buffer
15260            .read(cx)
15261            .text_anchor_for_position(selection.head(), cx)?;
15262        let (tail_buffer, cursor_buffer_position_end) = self
15263            .buffer
15264            .read(cx)
15265            .text_anchor_for_position(selection.tail(), cx)?;
15266        if tail_buffer != cursor_buffer {
15267            return None;
15268        }
15269
15270        let snapshot = cursor_buffer.read(cx).snapshot();
15271        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15272        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15273        let prepare_rename = provider
15274            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15275            .unwrap_or_else(|| Task::ready(Ok(None)));
15276        drop(snapshot);
15277
15278        Some(cx.spawn_in(window, async move |this, cx| {
15279            let rename_range = if let Some(range) = prepare_rename.await? {
15280                Some(range)
15281            } else {
15282                this.update(cx, |this, cx| {
15283                    let buffer = this.buffer.read(cx).snapshot(cx);
15284                    let mut buffer_highlights = this
15285                        .document_highlights_for_position(selection.head(), &buffer)
15286                        .filter(|highlight| {
15287                            highlight.start.excerpt_id == selection.head().excerpt_id
15288                                && highlight.end.excerpt_id == selection.head().excerpt_id
15289                        });
15290                    buffer_highlights
15291                        .next()
15292                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15293                })?
15294            };
15295            if let Some(rename_range) = rename_range {
15296                this.update_in(cx, |this, window, cx| {
15297                    let snapshot = cursor_buffer.read(cx).snapshot();
15298                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15299                    let cursor_offset_in_rename_range =
15300                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15301                    let cursor_offset_in_rename_range_end =
15302                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15303
15304                    this.take_rename(false, window, cx);
15305                    let buffer = this.buffer.read(cx).read(cx);
15306                    let cursor_offset = selection.head().to_offset(&buffer);
15307                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15308                    let rename_end = rename_start + rename_buffer_range.len();
15309                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15310                    let mut old_highlight_id = None;
15311                    let old_name: Arc<str> = buffer
15312                        .chunks(rename_start..rename_end, true)
15313                        .map(|chunk| {
15314                            if old_highlight_id.is_none() {
15315                                old_highlight_id = chunk.syntax_highlight_id;
15316                            }
15317                            chunk.text
15318                        })
15319                        .collect::<String>()
15320                        .into();
15321
15322                    drop(buffer);
15323
15324                    // Position the selection in the rename editor so that it matches the current selection.
15325                    this.show_local_selections = false;
15326                    let rename_editor = cx.new(|cx| {
15327                        let mut editor = Editor::single_line(window, cx);
15328                        editor.buffer.update(cx, |buffer, cx| {
15329                            buffer.edit([(0..0, old_name.clone())], None, cx)
15330                        });
15331                        let rename_selection_range = match cursor_offset_in_rename_range
15332                            .cmp(&cursor_offset_in_rename_range_end)
15333                        {
15334                            Ordering::Equal => {
15335                                editor.select_all(&SelectAll, window, cx);
15336                                return editor;
15337                            }
15338                            Ordering::Less => {
15339                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15340                            }
15341                            Ordering::Greater => {
15342                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15343                            }
15344                        };
15345                        if rename_selection_range.end > old_name.len() {
15346                            editor.select_all(&SelectAll, window, cx);
15347                        } else {
15348                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15349                                s.select_ranges([rename_selection_range]);
15350                            });
15351                        }
15352                        editor
15353                    });
15354                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15355                        if e == &EditorEvent::Focused {
15356                            cx.emit(EditorEvent::FocusedIn)
15357                        }
15358                    })
15359                    .detach();
15360
15361                    let write_highlights =
15362                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15363                    let read_highlights =
15364                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15365                    let ranges = write_highlights
15366                        .iter()
15367                        .flat_map(|(_, ranges)| ranges.iter())
15368                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15369                        .cloned()
15370                        .collect();
15371
15372                    this.highlight_text::<Rename>(
15373                        ranges,
15374                        HighlightStyle {
15375                            fade_out: Some(0.6),
15376                            ..Default::default()
15377                        },
15378                        cx,
15379                    );
15380                    let rename_focus_handle = rename_editor.focus_handle(cx);
15381                    window.focus(&rename_focus_handle);
15382                    let block_id = this.insert_blocks(
15383                        [BlockProperties {
15384                            style: BlockStyle::Flex,
15385                            placement: BlockPlacement::Below(range.start),
15386                            height: Some(1),
15387                            render: Arc::new({
15388                                let rename_editor = rename_editor.clone();
15389                                move |cx: &mut BlockContext| {
15390                                    let mut text_style = cx.editor_style.text.clone();
15391                                    if let Some(highlight_style) = old_highlight_id
15392                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15393                                    {
15394                                        text_style = text_style.highlight(highlight_style);
15395                                    }
15396                                    div()
15397                                        .block_mouse_except_scroll()
15398                                        .pl(cx.anchor_x)
15399                                        .child(EditorElement::new(
15400                                            &rename_editor,
15401                                            EditorStyle {
15402                                                background: cx.theme().system().transparent,
15403                                                local_player: cx.editor_style.local_player,
15404                                                text: text_style,
15405                                                scrollbar_width: cx.editor_style.scrollbar_width,
15406                                                syntax: cx.editor_style.syntax.clone(),
15407                                                status: cx.editor_style.status.clone(),
15408                                                inlay_hints_style: HighlightStyle {
15409                                                    font_weight: Some(FontWeight::BOLD),
15410                                                    ..make_inlay_hints_style(cx.app)
15411                                                },
15412                                                inline_completion_styles: make_suggestion_styles(
15413                                                    cx.app,
15414                                                ),
15415                                                ..EditorStyle::default()
15416                                            },
15417                                        ))
15418                                        .into_any_element()
15419                                }
15420                            }),
15421                            priority: 0,
15422                            render_in_minimap: true,
15423                        }],
15424                        Some(Autoscroll::fit()),
15425                        cx,
15426                    )[0];
15427                    this.pending_rename = Some(RenameState {
15428                        range,
15429                        old_name,
15430                        editor: rename_editor,
15431                        block_id,
15432                    });
15433                })?;
15434            }
15435
15436            Ok(())
15437        }))
15438    }
15439
15440    pub fn confirm_rename(
15441        &mut self,
15442        _: &ConfirmRename,
15443        window: &mut Window,
15444        cx: &mut Context<Self>,
15445    ) -> Option<Task<Result<()>>> {
15446        let rename = self.take_rename(false, window, cx)?;
15447        let workspace = self.workspace()?.downgrade();
15448        let (buffer, start) = self
15449            .buffer
15450            .read(cx)
15451            .text_anchor_for_position(rename.range.start, cx)?;
15452        let (end_buffer, _) = self
15453            .buffer
15454            .read(cx)
15455            .text_anchor_for_position(rename.range.end, cx)?;
15456        if buffer != end_buffer {
15457            return None;
15458        }
15459
15460        let old_name = rename.old_name;
15461        let new_name = rename.editor.read(cx).text(cx);
15462
15463        let rename = self.semantics_provider.as_ref()?.perform_rename(
15464            &buffer,
15465            start,
15466            new_name.clone(),
15467            cx,
15468        )?;
15469
15470        Some(cx.spawn_in(window, async move |editor, cx| {
15471            let project_transaction = rename.await?;
15472            Self::open_project_transaction(
15473                &editor,
15474                workspace,
15475                project_transaction,
15476                format!("Rename: {}{}", old_name, new_name),
15477                cx,
15478            )
15479            .await?;
15480
15481            editor.update(cx, |editor, cx| {
15482                editor.refresh_document_highlights(cx);
15483            })?;
15484            Ok(())
15485        }))
15486    }
15487
15488    fn take_rename(
15489        &mut self,
15490        moving_cursor: bool,
15491        window: &mut Window,
15492        cx: &mut Context<Self>,
15493    ) -> Option<RenameState> {
15494        let rename = self.pending_rename.take()?;
15495        if rename.editor.focus_handle(cx).is_focused(window) {
15496            window.focus(&self.focus_handle);
15497        }
15498
15499        self.remove_blocks(
15500            [rename.block_id].into_iter().collect(),
15501            Some(Autoscroll::fit()),
15502            cx,
15503        );
15504        self.clear_highlights::<Rename>(cx);
15505        self.show_local_selections = true;
15506
15507        if moving_cursor {
15508            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15509                editor.selections.newest::<usize>(cx).head()
15510            });
15511
15512            // Update the selection to match the position of the selection inside
15513            // the rename editor.
15514            let snapshot = self.buffer.read(cx).read(cx);
15515            let rename_range = rename.range.to_offset(&snapshot);
15516            let cursor_in_editor = snapshot
15517                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15518                .min(rename_range.end);
15519            drop(snapshot);
15520
15521            self.change_selections(None, window, cx, |s| {
15522                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15523            });
15524        } else {
15525            self.refresh_document_highlights(cx);
15526        }
15527
15528        Some(rename)
15529    }
15530
15531    pub fn pending_rename(&self) -> Option<&RenameState> {
15532        self.pending_rename.as_ref()
15533    }
15534
15535    fn format(
15536        &mut self,
15537        _: &Format,
15538        window: &mut Window,
15539        cx: &mut Context<Self>,
15540    ) -> Option<Task<Result<()>>> {
15541        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15542
15543        let project = match &self.project {
15544            Some(project) => project.clone(),
15545            None => return None,
15546        };
15547
15548        Some(self.perform_format(
15549            project,
15550            FormatTrigger::Manual,
15551            FormatTarget::Buffers,
15552            window,
15553            cx,
15554        ))
15555    }
15556
15557    fn format_selections(
15558        &mut self,
15559        _: &FormatSelections,
15560        window: &mut Window,
15561        cx: &mut Context<Self>,
15562    ) -> Option<Task<Result<()>>> {
15563        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15564
15565        let project = match &self.project {
15566            Some(project) => project.clone(),
15567            None => return None,
15568        };
15569
15570        let ranges = self
15571            .selections
15572            .all_adjusted(cx)
15573            .into_iter()
15574            .map(|selection| selection.range())
15575            .collect_vec();
15576
15577        Some(self.perform_format(
15578            project,
15579            FormatTrigger::Manual,
15580            FormatTarget::Ranges(ranges),
15581            window,
15582            cx,
15583        ))
15584    }
15585
15586    fn perform_format(
15587        &mut self,
15588        project: Entity<Project>,
15589        trigger: FormatTrigger,
15590        target: FormatTarget,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) -> Task<Result<()>> {
15594        let buffer = self.buffer.clone();
15595        let (buffers, target) = match target {
15596            FormatTarget::Buffers => {
15597                let mut buffers = buffer.read(cx).all_buffers();
15598                if trigger == FormatTrigger::Save {
15599                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15600                }
15601                (buffers, LspFormatTarget::Buffers)
15602            }
15603            FormatTarget::Ranges(selection_ranges) => {
15604                let multi_buffer = buffer.read(cx);
15605                let snapshot = multi_buffer.read(cx);
15606                let mut buffers = HashSet::default();
15607                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15608                    BTreeMap::new();
15609                for selection_range in selection_ranges {
15610                    for (buffer, buffer_range, _) in
15611                        snapshot.range_to_buffer_ranges(selection_range)
15612                    {
15613                        let buffer_id = buffer.remote_id();
15614                        let start = buffer.anchor_before(buffer_range.start);
15615                        let end = buffer.anchor_after(buffer_range.end);
15616                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15617                        buffer_id_to_ranges
15618                            .entry(buffer_id)
15619                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15620                            .or_insert_with(|| vec![start..end]);
15621                    }
15622                }
15623                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15624            }
15625        };
15626
15627        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15628        let selections_prev = transaction_id_prev
15629            .and_then(|transaction_id_prev| {
15630                // default to selections as they were after the last edit, if we have them,
15631                // instead of how they are now.
15632                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15633                // will take you back to where you made the last edit, instead of staying where you scrolled
15634                self.selection_history
15635                    .transaction(transaction_id_prev)
15636                    .map(|t| t.0.clone())
15637            })
15638            .unwrap_or_else(|| {
15639                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15640                self.selections.disjoint_anchors()
15641            });
15642
15643        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15644        let format = project.update(cx, |project, cx| {
15645            project.format(buffers, target, true, trigger, cx)
15646        });
15647
15648        cx.spawn_in(window, async move |editor, cx| {
15649            let transaction = futures::select_biased! {
15650                transaction = format.log_err().fuse() => transaction,
15651                () = timeout => {
15652                    log::warn!("timed out waiting for formatting");
15653                    None
15654                }
15655            };
15656
15657            buffer
15658                .update(cx, |buffer, cx| {
15659                    if let Some(transaction) = transaction {
15660                        if !buffer.is_singleton() {
15661                            buffer.push_transaction(&transaction.0, cx);
15662                        }
15663                    }
15664                    cx.notify();
15665                })
15666                .ok();
15667
15668            if let Some(transaction_id_now) =
15669                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15670            {
15671                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15672                if has_new_transaction {
15673                    _ = editor.update(cx, |editor, _| {
15674                        editor
15675                            .selection_history
15676                            .insert_transaction(transaction_id_now, selections_prev);
15677                    });
15678                }
15679            }
15680
15681            Ok(())
15682        })
15683    }
15684
15685    fn organize_imports(
15686        &mut self,
15687        _: &OrganizeImports,
15688        window: &mut Window,
15689        cx: &mut Context<Self>,
15690    ) -> Option<Task<Result<()>>> {
15691        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15692        let project = match &self.project {
15693            Some(project) => project.clone(),
15694            None => return None,
15695        };
15696        Some(self.perform_code_action_kind(
15697            project,
15698            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15699            window,
15700            cx,
15701        ))
15702    }
15703
15704    fn perform_code_action_kind(
15705        &mut self,
15706        project: Entity<Project>,
15707        kind: CodeActionKind,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Task<Result<()>> {
15711        let buffer = self.buffer.clone();
15712        let buffers = buffer.read(cx).all_buffers();
15713        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15714        let apply_action = project.update(cx, |project, cx| {
15715            project.apply_code_action_kind(buffers, kind, true, cx)
15716        });
15717        cx.spawn_in(window, async move |_, cx| {
15718            let transaction = futures::select_biased! {
15719                () = timeout => {
15720                    log::warn!("timed out waiting for executing code action");
15721                    None
15722                }
15723                transaction = apply_action.log_err().fuse() => transaction,
15724            };
15725            buffer
15726                .update(cx, |buffer, cx| {
15727                    // check if we need this
15728                    if let Some(transaction) = transaction {
15729                        if !buffer.is_singleton() {
15730                            buffer.push_transaction(&transaction.0, cx);
15731                        }
15732                    }
15733                    cx.notify();
15734                })
15735                .ok();
15736            Ok(())
15737        })
15738    }
15739
15740    fn restart_language_server(
15741        &mut self,
15742        _: &RestartLanguageServer,
15743        _: &mut Window,
15744        cx: &mut Context<Self>,
15745    ) {
15746        if let Some(project) = self.project.clone() {
15747            self.buffer.update(cx, |multi_buffer, cx| {
15748                project.update(cx, |project, cx| {
15749                    project.restart_language_servers_for_buffers(
15750                        multi_buffer.all_buffers().into_iter().collect(),
15751                        cx,
15752                    );
15753                });
15754            })
15755        }
15756    }
15757
15758    fn stop_language_server(
15759        &mut self,
15760        _: &StopLanguageServer,
15761        _: &mut Window,
15762        cx: &mut Context<Self>,
15763    ) {
15764        if let Some(project) = self.project.clone() {
15765            self.buffer.update(cx, |multi_buffer, cx| {
15766                project.update(cx, |project, cx| {
15767                    project.stop_language_servers_for_buffers(
15768                        multi_buffer.all_buffers().into_iter().collect(),
15769                        cx,
15770                    );
15771                    cx.emit(project::Event::RefreshInlayHints);
15772                });
15773            });
15774        }
15775    }
15776
15777    fn cancel_language_server_work(
15778        workspace: &mut Workspace,
15779        _: &actions::CancelLanguageServerWork,
15780        _: &mut Window,
15781        cx: &mut Context<Workspace>,
15782    ) {
15783        let project = workspace.project();
15784        let buffers = workspace
15785            .active_item(cx)
15786            .and_then(|item| item.act_as::<Editor>(cx))
15787            .map_or(HashSet::default(), |editor| {
15788                editor.read(cx).buffer.read(cx).all_buffers()
15789            });
15790        project.update(cx, |project, cx| {
15791            project.cancel_language_server_work_for_buffers(buffers, cx);
15792        });
15793    }
15794
15795    fn show_character_palette(
15796        &mut self,
15797        _: &ShowCharacterPalette,
15798        window: &mut Window,
15799        _: &mut Context<Self>,
15800    ) {
15801        window.show_character_palette();
15802    }
15803
15804    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15805        if self.mode.is_minimap() {
15806            return;
15807        }
15808
15809        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15810            let buffer = self.buffer.read(cx).snapshot(cx);
15811            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15812            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15813            let is_valid = buffer
15814                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15815                .any(|entry| {
15816                    entry.diagnostic.is_primary
15817                        && !entry.range.is_empty()
15818                        && entry.range.start == primary_range_start
15819                        && entry.diagnostic.message == active_diagnostics.active_message
15820                });
15821
15822            if !is_valid {
15823                self.dismiss_diagnostics(cx);
15824            }
15825        }
15826    }
15827
15828    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15829        match &self.active_diagnostics {
15830            ActiveDiagnostic::Group(group) => Some(group),
15831            _ => None,
15832        }
15833    }
15834
15835    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15836        self.dismiss_diagnostics(cx);
15837        self.active_diagnostics = ActiveDiagnostic::All;
15838    }
15839
15840    fn activate_diagnostics(
15841        &mut self,
15842        buffer_id: BufferId,
15843        diagnostic: DiagnosticEntry<usize>,
15844        window: &mut Window,
15845        cx: &mut Context<Self>,
15846    ) {
15847        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15848            return;
15849        }
15850        self.dismiss_diagnostics(cx);
15851        let snapshot = self.snapshot(window, cx);
15852        let buffer = self.buffer.read(cx).snapshot(cx);
15853        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15854            return;
15855        };
15856
15857        let diagnostic_group = buffer
15858            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15859            .collect::<Vec<_>>();
15860
15861        let blocks =
15862            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15863
15864        let blocks = self.display_map.update(cx, |display_map, cx| {
15865            display_map.insert_blocks(blocks, cx).into_iter().collect()
15866        });
15867        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15868            active_range: buffer.anchor_before(diagnostic.range.start)
15869                ..buffer.anchor_after(diagnostic.range.end),
15870            active_message: diagnostic.diagnostic.message.clone(),
15871            group_id: diagnostic.diagnostic.group_id,
15872            blocks,
15873        });
15874        cx.notify();
15875    }
15876
15877    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15878        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15879            return;
15880        };
15881
15882        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15883        if let ActiveDiagnostic::Group(group) = prev {
15884            self.display_map.update(cx, |display_map, cx| {
15885                display_map.remove_blocks(group.blocks, cx);
15886            });
15887            cx.notify();
15888        }
15889    }
15890
15891    /// Disable inline diagnostics rendering for this editor.
15892    pub fn disable_inline_diagnostics(&mut self) {
15893        self.inline_diagnostics_enabled = false;
15894        self.inline_diagnostics_update = Task::ready(());
15895        self.inline_diagnostics.clear();
15896    }
15897
15898    pub fn diagnostics_enabled(&self) -> bool {
15899        self.mode.is_full()
15900    }
15901
15902    pub fn inline_diagnostics_enabled(&self) -> bool {
15903        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15904    }
15905
15906    pub fn show_inline_diagnostics(&self) -> bool {
15907        self.show_inline_diagnostics
15908    }
15909
15910    pub fn toggle_inline_diagnostics(
15911        &mut self,
15912        _: &ToggleInlineDiagnostics,
15913        window: &mut Window,
15914        cx: &mut Context<Editor>,
15915    ) {
15916        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15917        self.refresh_inline_diagnostics(false, window, cx);
15918    }
15919
15920    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15921        self.diagnostics_max_severity = severity;
15922        self.display_map.update(cx, |display_map, _| {
15923            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15924        });
15925    }
15926
15927    pub fn toggle_diagnostics(
15928        &mut self,
15929        _: &ToggleDiagnostics,
15930        window: &mut Window,
15931        cx: &mut Context<Editor>,
15932    ) {
15933        if !self.diagnostics_enabled() {
15934            return;
15935        }
15936
15937        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15938            EditorSettings::get_global(cx)
15939                .diagnostics_max_severity
15940                .filter(|severity| severity != &DiagnosticSeverity::Off)
15941                .unwrap_or(DiagnosticSeverity::Hint)
15942        } else {
15943            DiagnosticSeverity::Off
15944        };
15945        self.set_max_diagnostics_severity(new_severity, cx);
15946        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15947            self.active_diagnostics = ActiveDiagnostic::None;
15948            self.inline_diagnostics_update = Task::ready(());
15949            self.inline_diagnostics.clear();
15950        } else {
15951            self.refresh_inline_diagnostics(false, window, cx);
15952        }
15953
15954        cx.notify();
15955    }
15956
15957    pub fn toggle_minimap(
15958        &mut self,
15959        _: &ToggleMinimap,
15960        window: &mut Window,
15961        cx: &mut Context<Editor>,
15962    ) {
15963        if self.supports_minimap(cx) {
15964            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15965        }
15966    }
15967
15968    fn refresh_inline_diagnostics(
15969        &mut self,
15970        debounce: bool,
15971        window: &mut Window,
15972        cx: &mut Context<Self>,
15973    ) {
15974        let max_severity = ProjectSettings::get_global(cx)
15975            .diagnostics
15976            .inline
15977            .max_severity
15978            .unwrap_or(self.diagnostics_max_severity);
15979
15980        if !self.inline_diagnostics_enabled()
15981            || !self.show_inline_diagnostics
15982            || max_severity == DiagnosticSeverity::Off
15983        {
15984            self.inline_diagnostics_update = Task::ready(());
15985            self.inline_diagnostics.clear();
15986            return;
15987        }
15988
15989        let debounce_ms = ProjectSettings::get_global(cx)
15990            .diagnostics
15991            .inline
15992            .update_debounce_ms;
15993        let debounce = if debounce && debounce_ms > 0 {
15994            Some(Duration::from_millis(debounce_ms))
15995        } else {
15996            None
15997        };
15998        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15999            if let Some(debounce) = debounce {
16000                cx.background_executor().timer(debounce).await;
16001            }
16002            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16003                editor
16004                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16005                    .ok()
16006            }) else {
16007                return;
16008            };
16009
16010            let new_inline_diagnostics = cx
16011                .background_spawn(async move {
16012                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16013                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16014                        let message = diagnostic_entry
16015                            .diagnostic
16016                            .message
16017                            .split_once('\n')
16018                            .map(|(line, _)| line)
16019                            .map(SharedString::new)
16020                            .unwrap_or_else(|| {
16021                                SharedString::from(diagnostic_entry.diagnostic.message)
16022                            });
16023                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16024                        let (Ok(i) | Err(i)) = inline_diagnostics
16025                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16026                        inline_diagnostics.insert(
16027                            i,
16028                            (
16029                                start_anchor,
16030                                InlineDiagnostic {
16031                                    message,
16032                                    group_id: diagnostic_entry.diagnostic.group_id,
16033                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16034                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16035                                    severity: diagnostic_entry.diagnostic.severity,
16036                                },
16037                            ),
16038                        );
16039                    }
16040                    inline_diagnostics
16041                })
16042                .await;
16043
16044            editor
16045                .update(cx, |editor, cx| {
16046                    editor.inline_diagnostics = new_inline_diagnostics;
16047                    cx.notify();
16048                })
16049                .ok();
16050        });
16051    }
16052
16053    fn pull_diagnostics(
16054        &mut self,
16055        buffer_id: Option<BufferId>,
16056        window: &Window,
16057        cx: &mut Context<Self>,
16058    ) -> Option<()> {
16059        let project = self.project.as_ref()?.downgrade();
16060        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16061            .diagnostics
16062            .lsp_pull_diagnostics;
16063        if !pull_diagnostics_settings.enabled {
16064            return None;
16065        }
16066        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16067        let mut buffers = self.buffer.read(cx).all_buffers();
16068        if let Some(buffer_id) = buffer_id {
16069            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16070        }
16071
16072        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16073            cx.background_executor().timer(debounce).await;
16074
16075            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16076                buffers
16077                    .into_iter()
16078                    .flat_map(|buffer| {
16079                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16080                    })
16081                    .collect::<FuturesUnordered<_>>()
16082            }) else {
16083                return;
16084            };
16085
16086            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16087                match pull_task {
16088                    Ok(()) => {
16089                        if editor
16090                            .update_in(cx, |editor, window, cx| {
16091                                editor.update_diagnostics_state(window, cx);
16092                            })
16093                            .is_err()
16094                        {
16095                            return;
16096                        }
16097                    }
16098                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16099                }
16100            }
16101        });
16102
16103        Some(())
16104    }
16105
16106    pub fn set_selections_from_remote(
16107        &mut self,
16108        selections: Vec<Selection<Anchor>>,
16109        pending_selection: Option<Selection<Anchor>>,
16110        window: &mut Window,
16111        cx: &mut Context<Self>,
16112    ) {
16113        let old_cursor_position = self.selections.newest_anchor().head();
16114        self.selections.change_with(cx, |s| {
16115            s.select_anchors(selections);
16116            if let Some(pending_selection) = pending_selection {
16117                s.set_pending(pending_selection, SelectMode::Character);
16118            } else {
16119                s.clear_pending();
16120            }
16121        });
16122        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16123    }
16124
16125    pub fn transact(
16126        &mut self,
16127        window: &mut Window,
16128        cx: &mut Context<Self>,
16129        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16130    ) -> Option<TransactionId> {
16131        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16132            this.start_transaction_at(Instant::now(), window, cx);
16133            update(this, window, cx);
16134            this.end_transaction_at(Instant::now(), cx)
16135        })
16136    }
16137
16138    pub fn start_transaction_at(
16139        &mut self,
16140        now: Instant,
16141        window: &mut Window,
16142        cx: &mut Context<Self>,
16143    ) {
16144        self.end_selection(window, cx);
16145        if let Some(tx_id) = self
16146            .buffer
16147            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16148        {
16149            self.selection_history
16150                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16151            cx.emit(EditorEvent::TransactionBegun {
16152                transaction_id: tx_id,
16153            })
16154        }
16155    }
16156
16157    pub fn end_transaction_at(
16158        &mut self,
16159        now: Instant,
16160        cx: &mut Context<Self>,
16161    ) -> Option<TransactionId> {
16162        if let Some(transaction_id) = self
16163            .buffer
16164            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16165        {
16166            if let Some((_, end_selections)) =
16167                self.selection_history.transaction_mut(transaction_id)
16168            {
16169                *end_selections = Some(self.selections.disjoint_anchors());
16170            } else {
16171                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16172            }
16173
16174            cx.emit(EditorEvent::Edited { transaction_id });
16175            Some(transaction_id)
16176        } else {
16177            None
16178        }
16179    }
16180
16181    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16182        if self.selection_mark_mode {
16183            self.change_selections(None, window, cx, |s| {
16184                s.move_with(|_, sel| {
16185                    sel.collapse_to(sel.head(), SelectionGoal::None);
16186                });
16187            })
16188        }
16189        self.selection_mark_mode = true;
16190        cx.notify();
16191    }
16192
16193    pub fn swap_selection_ends(
16194        &mut self,
16195        _: &actions::SwapSelectionEnds,
16196        window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        self.change_selections(None, window, cx, |s| {
16200            s.move_with(|_, sel| {
16201                if sel.start != sel.end {
16202                    sel.reversed = !sel.reversed
16203                }
16204            });
16205        });
16206        self.request_autoscroll(Autoscroll::newest(), cx);
16207        cx.notify();
16208    }
16209
16210    pub fn toggle_fold(
16211        &mut self,
16212        _: &actions::ToggleFold,
16213        window: &mut Window,
16214        cx: &mut Context<Self>,
16215    ) {
16216        if self.is_singleton(cx) {
16217            let selection = self.selections.newest::<Point>(cx);
16218
16219            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16220            let range = if selection.is_empty() {
16221                let point = selection.head().to_display_point(&display_map);
16222                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16223                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16224                    .to_point(&display_map);
16225                start..end
16226            } else {
16227                selection.range()
16228            };
16229            if display_map.folds_in_range(range).next().is_some() {
16230                self.unfold_lines(&Default::default(), window, cx)
16231            } else {
16232                self.fold(&Default::default(), window, cx)
16233            }
16234        } else {
16235            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16236            let buffer_ids: HashSet<_> = self
16237                .selections
16238                .disjoint_anchor_ranges()
16239                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16240                .collect();
16241
16242            let should_unfold = buffer_ids
16243                .iter()
16244                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16245
16246            for buffer_id in buffer_ids {
16247                if should_unfold {
16248                    self.unfold_buffer(buffer_id, cx);
16249                } else {
16250                    self.fold_buffer(buffer_id, cx);
16251                }
16252            }
16253        }
16254    }
16255
16256    pub fn toggle_fold_recursive(
16257        &mut self,
16258        _: &actions::ToggleFoldRecursive,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) {
16262        let selection = self.selections.newest::<Point>(cx);
16263
16264        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16265        let range = if selection.is_empty() {
16266            let point = selection.head().to_display_point(&display_map);
16267            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16268            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16269                .to_point(&display_map);
16270            start..end
16271        } else {
16272            selection.range()
16273        };
16274        if display_map.folds_in_range(range).next().is_some() {
16275            self.unfold_recursive(&Default::default(), window, cx)
16276        } else {
16277            self.fold_recursive(&Default::default(), window, cx)
16278        }
16279    }
16280
16281    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16282        if self.is_singleton(cx) {
16283            let mut to_fold = Vec::new();
16284            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16285            let selections = self.selections.all_adjusted(cx);
16286
16287            for selection in selections {
16288                let range = selection.range().sorted();
16289                let buffer_start_row = range.start.row;
16290
16291                if range.start.row != range.end.row {
16292                    let mut found = false;
16293                    let mut row = range.start.row;
16294                    while row <= range.end.row {
16295                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16296                        {
16297                            found = true;
16298                            row = crease.range().end.row + 1;
16299                            to_fold.push(crease);
16300                        } else {
16301                            row += 1
16302                        }
16303                    }
16304                    if found {
16305                        continue;
16306                    }
16307                }
16308
16309                for row in (0..=range.start.row).rev() {
16310                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16311                        if crease.range().end.row >= buffer_start_row {
16312                            to_fold.push(crease);
16313                            if row <= range.start.row {
16314                                break;
16315                            }
16316                        }
16317                    }
16318                }
16319            }
16320
16321            self.fold_creases(to_fold, true, window, cx);
16322        } else {
16323            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16324            let buffer_ids = self
16325                .selections
16326                .disjoint_anchor_ranges()
16327                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16328                .collect::<HashSet<_>>();
16329            for buffer_id in buffer_ids {
16330                self.fold_buffer(buffer_id, cx);
16331            }
16332        }
16333    }
16334
16335    fn fold_at_level(
16336        &mut self,
16337        fold_at: &FoldAtLevel,
16338        window: &mut Window,
16339        cx: &mut Context<Self>,
16340    ) {
16341        if !self.buffer.read(cx).is_singleton() {
16342            return;
16343        }
16344
16345        let fold_at_level = fold_at.0;
16346        let snapshot = self.buffer.read(cx).snapshot(cx);
16347        let mut to_fold = Vec::new();
16348        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16349
16350        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16351            while start_row < end_row {
16352                match self
16353                    .snapshot(window, cx)
16354                    .crease_for_buffer_row(MultiBufferRow(start_row))
16355                {
16356                    Some(crease) => {
16357                        let nested_start_row = crease.range().start.row + 1;
16358                        let nested_end_row = crease.range().end.row;
16359
16360                        if current_level < fold_at_level {
16361                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16362                        } else if current_level == fold_at_level {
16363                            to_fold.push(crease);
16364                        }
16365
16366                        start_row = nested_end_row + 1;
16367                    }
16368                    None => start_row += 1,
16369                }
16370            }
16371        }
16372
16373        self.fold_creases(to_fold, true, window, cx);
16374    }
16375
16376    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16377        if self.buffer.read(cx).is_singleton() {
16378            let mut fold_ranges = Vec::new();
16379            let snapshot = self.buffer.read(cx).snapshot(cx);
16380
16381            for row in 0..snapshot.max_row().0 {
16382                if let Some(foldable_range) = self
16383                    .snapshot(window, cx)
16384                    .crease_for_buffer_row(MultiBufferRow(row))
16385                {
16386                    fold_ranges.push(foldable_range);
16387                }
16388            }
16389
16390            self.fold_creases(fold_ranges, true, window, cx);
16391        } else {
16392            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16393                editor
16394                    .update_in(cx, |editor, _, cx| {
16395                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16396                            editor.fold_buffer(buffer_id, cx);
16397                        }
16398                    })
16399                    .ok();
16400            });
16401        }
16402    }
16403
16404    pub fn fold_function_bodies(
16405        &mut self,
16406        _: &actions::FoldFunctionBodies,
16407        window: &mut Window,
16408        cx: &mut Context<Self>,
16409    ) {
16410        let snapshot = self.buffer.read(cx).snapshot(cx);
16411
16412        let ranges = snapshot
16413            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16414            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16415            .collect::<Vec<_>>();
16416
16417        let creases = ranges
16418            .into_iter()
16419            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16420            .collect();
16421
16422        self.fold_creases(creases, true, window, cx);
16423    }
16424
16425    pub fn fold_recursive(
16426        &mut self,
16427        _: &actions::FoldRecursive,
16428        window: &mut Window,
16429        cx: &mut Context<Self>,
16430    ) {
16431        let mut to_fold = Vec::new();
16432        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16433        let selections = self.selections.all_adjusted(cx);
16434
16435        for selection in selections {
16436            let range = selection.range().sorted();
16437            let buffer_start_row = range.start.row;
16438
16439            if range.start.row != range.end.row {
16440                let mut found = false;
16441                for row in range.start.row..=range.end.row {
16442                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16443                        found = true;
16444                        to_fold.push(crease);
16445                    }
16446                }
16447                if found {
16448                    continue;
16449                }
16450            }
16451
16452            for row in (0..=range.start.row).rev() {
16453                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16454                    if crease.range().end.row >= buffer_start_row {
16455                        to_fold.push(crease);
16456                    } else {
16457                        break;
16458                    }
16459                }
16460            }
16461        }
16462
16463        self.fold_creases(to_fold, true, window, cx);
16464    }
16465
16466    pub fn fold_at(
16467        &mut self,
16468        buffer_row: MultiBufferRow,
16469        window: &mut Window,
16470        cx: &mut Context<Self>,
16471    ) {
16472        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16473
16474        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16475            let autoscroll = self
16476                .selections
16477                .all::<Point>(cx)
16478                .iter()
16479                .any(|selection| crease.range().overlaps(&selection.range()));
16480
16481            self.fold_creases(vec![crease], autoscroll, window, cx);
16482        }
16483    }
16484
16485    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16486        if self.is_singleton(cx) {
16487            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16488            let buffer = &display_map.buffer_snapshot;
16489            let selections = self.selections.all::<Point>(cx);
16490            let ranges = selections
16491                .iter()
16492                .map(|s| {
16493                    let range = s.display_range(&display_map).sorted();
16494                    let mut start = range.start.to_point(&display_map);
16495                    let mut end = range.end.to_point(&display_map);
16496                    start.column = 0;
16497                    end.column = buffer.line_len(MultiBufferRow(end.row));
16498                    start..end
16499                })
16500                .collect::<Vec<_>>();
16501
16502            self.unfold_ranges(&ranges, true, true, cx);
16503        } else {
16504            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16505            let buffer_ids = self
16506                .selections
16507                .disjoint_anchor_ranges()
16508                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16509                .collect::<HashSet<_>>();
16510            for buffer_id in buffer_ids {
16511                self.unfold_buffer(buffer_id, cx);
16512            }
16513        }
16514    }
16515
16516    pub fn unfold_recursive(
16517        &mut self,
16518        _: &UnfoldRecursive,
16519        _window: &mut Window,
16520        cx: &mut Context<Self>,
16521    ) {
16522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16523        let selections = self.selections.all::<Point>(cx);
16524        let ranges = selections
16525            .iter()
16526            .map(|s| {
16527                let mut range = s.display_range(&display_map).sorted();
16528                *range.start.column_mut() = 0;
16529                *range.end.column_mut() = display_map.line_len(range.end.row());
16530                let start = range.start.to_point(&display_map);
16531                let end = range.end.to_point(&display_map);
16532                start..end
16533            })
16534            .collect::<Vec<_>>();
16535
16536        self.unfold_ranges(&ranges, true, true, cx);
16537    }
16538
16539    pub fn unfold_at(
16540        &mut self,
16541        buffer_row: MultiBufferRow,
16542        _window: &mut Window,
16543        cx: &mut Context<Self>,
16544    ) {
16545        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16546
16547        let intersection_range = Point::new(buffer_row.0, 0)
16548            ..Point::new(
16549                buffer_row.0,
16550                display_map.buffer_snapshot.line_len(buffer_row),
16551            );
16552
16553        let autoscroll = self
16554            .selections
16555            .all::<Point>(cx)
16556            .iter()
16557            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16558
16559        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16560    }
16561
16562    pub fn unfold_all(
16563        &mut self,
16564        _: &actions::UnfoldAll,
16565        _window: &mut Window,
16566        cx: &mut Context<Self>,
16567    ) {
16568        if self.buffer.read(cx).is_singleton() {
16569            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16570            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16571        } else {
16572            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16573                editor
16574                    .update(cx, |editor, cx| {
16575                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16576                            editor.unfold_buffer(buffer_id, cx);
16577                        }
16578                    })
16579                    .ok();
16580            });
16581        }
16582    }
16583
16584    pub fn fold_selected_ranges(
16585        &mut self,
16586        _: &FoldSelectedRanges,
16587        window: &mut Window,
16588        cx: &mut Context<Self>,
16589    ) {
16590        let selections = self.selections.all_adjusted(cx);
16591        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16592        let ranges = selections
16593            .into_iter()
16594            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16595            .collect::<Vec<_>>();
16596        self.fold_creases(ranges, true, window, cx);
16597    }
16598
16599    pub fn fold_ranges<T: ToOffset + Clone>(
16600        &mut self,
16601        ranges: Vec<Range<T>>,
16602        auto_scroll: bool,
16603        window: &mut Window,
16604        cx: &mut Context<Self>,
16605    ) {
16606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16607        let ranges = ranges
16608            .into_iter()
16609            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16610            .collect::<Vec<_>>();
16611        self.fold_creases(ranges, auto_scroll, window, cx);
16612    }
16613
16614    pub fn fold_creases<T: ToOffset + Clone>(
16615        &mut self,
16616        creases: Vec<Crease<T>>,
16617        auto_scroll: bool,
16618        _window: &mut Window,
16619        cx: &mut Context<Self>,
16620    ) {
16621        if creases.is_empty() {
16622            return;
16623        }
16624
16625        let mut buffers_affected = HashSet::default();
16626        let multi_buffer = self.buffer().read(cx);
16627        for crease in &creases {
16628            if let Some((_, buffer, _)) =
16629                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16630            {
16631                buffers_affected.insert(buffer.read(cx).remote_id());
16632            };
16633        }
16634
16635        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16636
16637        if auto_scroll {
16638            self.request_autoscroll(Autoscroll::fit(), cx);
16639        }
16640
16641        cx.notify();
16642
16643        self.scrollbar_marker_state.dirty = true;
16644        self.folds_did_change(cx);
16645    }
16646
16647    /// Removes any folds whose ranges intersect any of the given ranges.
16648    pub fn unfold_ranges<T: ToOffset + Clone>(
16649        &mut self,
16650        ranges: &[Range<T>],
16651        inclusive: bool,
16652        auto_scroll: bool,
16653        cx: &mut Context<Self>,
16654    ) {
16655        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16656            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16657        });
16658        self.folds_did_change(cx);
16659    }
16660
16661    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16662        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16663            return;
16664        }
16665        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16666        self.display_map.update(cx, |display_map, cx| {
16667            display_map.fold_buffers([buffer_id], cx)
16668        });
16669        cx.emit(EditorEvent::BufferFoldToggled {
16670            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16671            folded: true,
16672        });
16673        cx.notify();
16674    }
16675
16676    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16677        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16678            return;
16679        }
16680        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16681        self.display_map.update(cx, |display_map, cx| {
16682            display_map.unfold_buffers([buffer_id], cx);
16683        });
16684        cx.emit(EditorEvent::BufferFoldToggled {
16685            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16686            folded: false,
16687        });
16688        cx.notify();
16689    }
16690
16691    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16692        self.display_map.read(cx).is_buffer_folded(buffer)
16693    }
16694
16695    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16696        self.display_map.read(cx).folded_buffers()
16697    }
16698
16699    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16700        self.display_map.update(cx, |display_map, cx| {
16701            display_map.disable_header_for_buffer(buffer_id, cx);
16702        });
16703        cx.notify();
16704    }
16705
16706    /// Removes any folds with the given ranges.
16707    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16708        &mut self,
16709        ranges: &[Range<T>],
16710        type_id: TypeId,
16711        auto_scroll: bool,
16712        cx: &mut Context<Self>,
16713    ) {
16714        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16715            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16716        });
16717        self.folds_did_change(cx);
16718    }
16719
16720    fn remove_folds_with<T: ToOffset + Clone>(
16721        &mut self,
16722        ranges: &[Range<T>],
16723        auto_scroll: bool,
16724        cx: &mut Context<Self>,
16725        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16726    ) {
16727        if ranges.is_empty() {
16728            return;
16729        }
16730
16731        let mut buffers_affected = HashSet::default();
16732        let multi_buffer = self.buffer().read(cx);
16733        for range in ranges {
16734            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16735                buffers_affected.insert(buffer.read(cx).remote_id());
16736            };
16737        }
16738
16739        self.display_map.update(cx, update);
16740
16741        if auto_scroll {
16742            self.request_autoscroll(Autoscroll::fit(), cx);
16743        }
16744
16745        cx.notify();
16746        self.scrollbar_marker_state.dirty = true;
16747        self.active_indent_guides_state.dirty = true;
16748    }
16749
16750    pub fn update_fold_widths(
16751        &mut self,
16752        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16753        cx: &mut Context<Self>,
16754    ) -> bool {
16755        self.display_map
16756            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16757    }
16758
16759    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16760        self.display_map.read(cx).fold_placeholder.clone()
16761    }
16762
16763    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16764        self.buffer.update(cx, |buffer, cx| {
16765            buffer.set_all_diff_hunks_expanded(cx);
16766        });
16767    }
16768
16769    pub fn expand_all_diff_hunks(
16770        &mut self,
16771        _: &ExpandAllDiffHunks,
16772        _window: &mut Window,
16773        cx: &mut Context<Self>,
16774    ) {
16775        self.buffer.update(cx, |buffer, cx| {
16776            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16777        });
16778    }
16779
16780    pub fn toggle_selected_diff_hunks(
16781        &mut self,
16782        _: &ToggleSelectedDiffHunks,
16783        _window: &mut Window,
16784        cx: &mut Context<Self>,
16785    ) {
16786        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16787        self.toggle_diff_hunks_in_ranges(ranges, cx);
16788    }
16789
16790    pub fn diff_hunks_in_ranges<'a>(
16791        &'a self,
16792        ranges: &'a [Range<Anchor>],
16793        buffer: &'a MultiBufferSnapshot,
16794    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16795        ranges.iter().flat_map(move |range| {
16796            let end_excerpt_id = range.end.excerpt_id;
16797            let range = range.to_point(buffer);
16798            let mut peek_end = range.end;
16799            if range.end.row < buffer.max_row().0 {
16800                peek_end = Point::new(range.end.row + 1, 0);
16801            }
16802            buffer
16803                .diff_hunks_in_range(range.start..peek_end)
16804                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16805        })
16806    }
16807
16808    pub fn has_stageable_diff_hunks_in_ranges(
16809        &self,
16810        ranges: &[Range<Anchor>],
16811        snapshot: &MultiBufferSnapshot,
16812    ) -> bool {
16813        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16814        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16815    }
16816
16817    pub fn toggle_staged_selected_diff_hunks(
16818        &mut self,
16819        _: &::git::ToggleStaged,
16820        _: &mut Window,
16821        cx: &mut Context<Self>,
16822    ) {
16823        let snapshot = self.buffer.read(cx).snapshot(cx);
16824        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16825        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16826        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16827    }
16828
16829    pub fn set_render_diff_hunk_controls(
16830        &mut self,
16831        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16832        cx: &mut Context<Self>,
16833    ) {
16834        self.render_diff_hunk_controls = render_diff_hunk_controls;
16835        cx.notify();
16836    }
16837
16838    pub fn stage_and_next(
16839        &mut self,
16840        _: &::git::StageAndNext,
16841        window: &mut Window,
16842        cx: &mut Context<Self>,
16843    ) {
16844        self.do_stage_or_unstage_and_next(true, window, cx);
16845    }
16846
16847    pub fn unstage_and_next(
16848        &mut self,
16849        _: &::git::UnstageAndNext,
16850        window: &mut Window,
16851        cx: &mut Context<Self>,
16852    ) {
16853        self.do_stage_or_unstage_and_next(false, window, cx);
16854    }
16855
16856    pub fn stage_or_unstage_diff_hunks(
16857        &mut self,
16858        stage: bool,
16859        ranges: Vec<Range<Anchor>>,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16863        cx.spawn(async move |this, cx| {
16864            task.await?;
16865            this.update(cx, |this, cx| {
16866                let snapshot = this.buffer.read(cx).snapshot(cx);
16867                let chunk_by = this
16868                    .diff_hunks_in_ranges(&ranges, &snapshot)
16869                    .chunk_by(|hunk| hunk.buffer_id);
16870                for (buffer_id, hunks) in &chunk_by {
16871                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16872                }
16873            })
16874        })
16875        .detach_and_log_err(cx);
16876    }
16877
16878    fn save_buffers_for_ranges_if_needed(
16879        &mut self,
16880        ranges: &[Range<Anchor>],
16881        cx: &mut Context<Editor>,
16882    ) -> Task<Result<()>> {
16883        let multibuffer = self.buffer.read(cx);
16884        let snapshot = multibuffer.read(cx);
16885        let buffer_ids: HashSet<_> = ranges
16886            .iter()
16887            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16888            .collect();
16889        drop(snapshot);
16890
16891        let mut buffers = HashSet::default();
16892        for buffer_id in buffer_ids {
16893            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16894                let buffer = buffer_entity.read(cx);
16895                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16896                {
16897                    buffers.insert(buffer_entity);
16898                }
16899            }
16900        }
16901
16902        if let Some(project) = &self.project {
16903            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16904        } else {
16905            Task::ready(Ok(()))
16906        }
16907    }
16908
16909    fn do_stage_or_unstage_and_next(
16910        &mut self,
16911        stage: bool,
16912        window: &mut Window,
16913        cx: &mut Context<Self>,
16914    ) {
16915        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16916
16917        if ranges.iter().any(|range| range.start != range.end) {
16918            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16919            return;
16920        }
16921
16922        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16923        let snapshot = self.snapshot(window, cx);
16924        let position = self.selections.newest::<Point>(cx).head();
16925        let mut row = snapshot
16926            .buffer_snapshot
16927            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16928            .find(|hunk| hunk.row_range.start.0 > position.row)
16929            .map(|hunk| hunk.row_range.start);
16930
16931        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16932        // Outside of the project diff editor, wrap around to the beginning.
16933        if !all_diff_hunks_expanded {
16934            row = row.or_else(|| {
16935                snapshot
16936                    .buffer_snapshot
16937                    .diff_hunks_in_range(Point::zero()..position)
16938                    .find(|hunk| hunk.row_range.end.0 < position.row)
16939                    .map(|hunk| hunk.row_range.start)
16940            });
16941        }
16942
16943        if let Some(row) = row {
16944            let destination = Point::new(row.0, 0);
16945            let autoscroll = Autoscroll::center();
16946
16947            self.unfold_ranges(&[destination..destination], false, false, cx);
16948            self.change_selections(Some(autoscroll), window, cx, |s| {
16949                s.select_ranges([destination..destination]);
16950            });
16951        }
16952    }
16953
16954    fn do_stage_or_unstage(
16955        &self,
16956        stage: bool,
16957        buffer_id: BufferId,
16958        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16959        cx: &mut App,
16960    ) -> Option<()> {
16961        let project = self.project.as_ref()?;
16962        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16963        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16964        let buffer_snapshot = buffer.read(cx).snapshot();
16965        let file_exists = buffer_snapshot
16966            .file()
16967            .is_some_and(|file| file.disk_state().exists());
16968        diff.update(cx, |diff, cx| {
16969            diff.stage_or_unstage_hunks(
16970                stage,
16971                &hunks
16972                    .map(|hunk| buffer_diff::DiffHunk {
16973                        buffer_range: hunk.buffer_range,
16974                        diff_base_byte_range: hunk.diff_base_byte_range,
16975                        secondary_status: hunk.secondary_status,
16976                        range: Point::zero()..Point::zero(), // unused
16977                    })
16978                    .collect::<Vec<_>>(),
16979                &buffer_snapshot,
16980                file_exists,
16981                cx,
16982            )
16983        });
16984        None
16985    }
16986
16987    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16988        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16989        self.buffer
16990            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16991    }
16992
16993    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16994        self.buffer.update(cx, |buffer, cx| {
16995            let ranges = vec![Anchor::min()..Anchor::max()];
16996            if !buffer.all_diff_hunks_expanded()
16997                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16998            {
16999                buffer.collapse_diff_hunks(ranges, cx);
17000                true
17001            } else {
17002                false
17003            }
17004        })
17005    }
17006
17007    fn toggle_diff_hunks_in_ranges(
17008        &mut self,
17009        ranges: Vec<Range<Anchor>>,
17010        cx: &mut Context<Editor>,
17011    ) {
17012        self.buffer.update(cx, |buffer, cx| {
17013            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17014            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17015        })
17016    }
17017
17018    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17019        self.buffer.update(cx, |buffer, cx| {
17020            let snapshot = buffer.snapshot(cx);
17021            let excerpt_id = range.end.excerpt_id;
17022            let point_range = range.to_point(&snapshot);
17023            let expand = !buffer.single_hunk_is_expanded(range, cx);
17024            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17025        })
17026    }
17027
17028    pub(crate) fn apply_all_diff_hunks(
17029        &mut self,
17030        _: &ApplyAllDiffHunks,
17031        window: &mut Window,
17032        cx: &mut Context<Self>,
17033    ) {
17034        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17035
17036        let buffers = self.buffer.read(cx).all_buffers();
17037        for branch_buffer in buffers {
17038            branch_buffer.update(cx, |branch_buffer, cx| {
17039                branch_buffer.merge_into_base(Vec::new(), cx);
17040            });
17041        }
17042
17043        if let Some(project) = self.project.clone() {
17044            self.save(true, project, window, cx).detach_and_log_err(cx);
17045        }
17046    }
17047
17048    pub(crate) fn apply_selected_diff_hunks(
17049        &mut self,
17050        _: &ApplyDiffHunk,
17051        window: &mut Window,
17052        cx: &mut Context<Self>,
17053    ) {
17054        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17055        let snapshot = self.snapshot(window, cx);
17056        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17057        let mut ranges_by_buffer = HashMap::default();
17058        self.transact(window, cx, |editor, _window, cx| {
17059            for hunk in hunks {
17060                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17061                    ranges_by_buffer
17062                        .entry(buffer.clone())
17063                        .or_insert_with(Vec::new)
17064                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17065                }
17066            }
17067
17068            for (buffer, ranges) in ranges_by_buffer {
17069                buffer.update(cx, |buffer, cx| {
17070                    buffer.merge_into_base(ranges, cx);
17071                });
17072            }
17073        });
17074
17075        if let Some(project) = self.project.clone() {
17076            self.save(true, project, window, cx).detach_and_log_err(cx);
17077        }
17078    }
17079
17080    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17081        if hovered != self.gutter_hovered {
17082            self.gutter_hovered = hovered;
17083            cx.notify();
17084        }
17085    }
17086
17087    pub fn insert_blocks(
17088        &mut self,
17089        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17090        autoscroll: Option<Autoscroll>,
17091        cx: &mut Context<Self>,
17092    ) -> Vec<CustomBlockId> {
17093        let blocks = self
17094            .display_map
17095            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17096        if let Some(autoscroll) = autoscroll {
17097            self.request_autoscroll(autoscroll, cx);
17098        }
17099        cx.notify();
17100        blocks
17101    }
17102
17103    pub fn resize_blocks(
17104        &mut self,
17105        heights: HashMap<CustomBlockId, u32>,
17106        autoscroll: Option<Autoscroll>,
17107        cx: &mut Context<Self>,
17108    ) {
17109        self.display_map
17110            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17111        if let Some(autoscroll) = autoscroll {
17112            self.request_autoscroll(autoscroll, cx);
17113        }
17114        cx.notify();
17115    }
17116
17117    pub fn replace_blocks(
17118        &mut self,
17119        renderers: HashMap<CustomBlockId, RenderBlock>,
17120        autoscroll: Option<Autoscroll>,
17121        cx: &mut Context<Self>,
17122    ) {
17123        self.display_map
17124            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17125        if let Some(autoscroll) = autoscroll {
17126            self.request_autoscroll(autoscroll, cx);
17127        }
17128        cx.notify();
17129    }
17130
17131    pub fn remove_blocks(
17132        &mut self,
17133        block_ids: HashSet<CustomBlockId>,
17134        autoscroll: Option<Autoscroll>,
17135        cx: &mut Context<Self>,
17136    ) {
17137        self.display_map.update(cx, |display_map, cx| {
17138            display_map.remove_blocks(block_ids, cx)
17139        });
17140        if let Some(autoscroll) = autoscroll {
17141            self.request_autoscroll(autoscroll, cx);
17142        }
17143        cx.notify();
17144    }
17145
17146    pub fn row_for_block(
17147        &self,
17148        block_id: CustomBlockId,
17149        cx: &mut Context<Self>,
17150    ) -> Option<DisplayRow> {
17151        self.display_map
17152            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17153    }
17154
17155    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17156        self.focused_block = Some(focused_block);
17157    }
17158
17159    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17160        self.focused_block.take()
17161    }
17162
17163    pub fn insert_creases(
17164        &mut self,
17165        creases: impl IntoIterator<Item = Crease<Anchor>>,
17166        cx: &mut Context<Self>,
17167    ) -> Vec<CreaseId> {
17168        self.display_map
17169            .update(cx, |map, cx| map.insert_creases(creases, cx))
17170    }
17171
17172    pub fn remove_creases(
17173        &mut self,
17174        ids: impl IntoIterator<Item = CreaseId>,
17175        cx: &mut Context<Self>,
17176    ) -> Vec<(CreaseId, Range<Anchor>)> {
17177        self.display_map
17178            .update(cx, |map, cx| map.remove_creases(ids, cx))
17179    }
17180
17181    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17182        self.display_map
17183            .update(cx, |map, cx| map.snapshot(cx))
17184            .longest_row()
17185    }
17186
17187    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17188        self.display_map
17189            .update(cx, |map, cx| map.snapshot(cx))
17190            .max_point()
17191    }
17192
17193    pub fn text(&self, cx: &App) -> String {
17194        self.buffer.read(cx).read(cx).text()
17195    }
17196
17197    pub fn is_empty(&self, cx: &App) -> bool {
17198        self.buffer.read(cx).read(cx).is_empty()
17199    }
17200
17201    pub fn text_option(&self, cx: &App) -> Option<String> {
17202        let text = self.text(cx);
17203        let text = text.trim();
17204
17205        if text.is_empty() {
17206            return None;
17207        }
17208
17209        Some(text.to_string())
17210    }
17211
17212    pub fn set_text(
17213        &mut self,
17214        text: impl Into<Arc<str>>,
17215        window: &mut Window,
17216        cx: &mut Context<Self>,
17217    ) {
17218        self.transact(window, cx, |this, _, cx| {
17219            this.buffer
17220                .read(cx)
17221                .as_singleton()
17222                .expect("you can only call set_text on editors for singleton buffers")
17223                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17224        });
17225    }
17226
17227    pub fn display_text(&self, cx: &mut App) -> String {
17228        self.display_map
17229            .update(cx, |map, cx| map.snapshot(cx))
17230            .text()
17231    }
17232
17233    fn create_minimap(
17234        &self,
17235        minimap_settings: MinimapSettings,
17236        window: &mut Window,
17237        cx: &mut Context<Self>,
17238    ) -> Option<Entity<Self>> {
17239        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17240            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17241    }
17242
17243    fn initialize_new_minimap(
17244        &self,
17245        minimap_settings: MinimapSettings,
17246        window: &mut Window,
17247        cx: &mut Context<Self>,
17248    ) -> Entity<Self> {
17249        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17250
17251        let mut minimap = Editor::new_internal(
17252            EditorMode::Minimap {
17253                parent: cx.weak_entity(),
17254            },
17255            self.buffer.clone(),
17256            self.project.clone(),
17257            Some(self.display_map.clone()),
17258            window,
17259            cx,
17260        );
17261        minimap.scroll_manager.clone_state(&self.scroll_manager);
17262        minimap.set_text_style_refinement(TextStyleRefinement {
17263            font_size: Some(MINIMAP_FONT_SIZE),
17264            font_weight: Some(MINIMAP_FONT_WEIGHT),
17265            ..Default::default()
17266        });
17267        minimap.update_minimap_configuration(minimap_settings, cx);
17268        cx.new(|_| minimap)
17269    }
17270
17271    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17272        let current_line_highlight = minimap_settings
17273            .current_line_highlight
17274            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17275        self.set_current_line_highlight(Some(current_line_highlight));
17276    }
17277
17278    pub fn minimap(&self) -> Option<&Entity<Self>> {
17279        self.minimap
17280            .as_ref()
17281            .filter(|_| self.minimap_visibility.visible())
17282    }
17283
17284    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17285        let mut wrap_guides = smallvec![];
17286
17287        if self.show_wrap_guides == Some(false) {
17288            return wrap_guides;
17289        }
17290
17291        let settings = self.buffer.read(cx).language_settings(cx);
17292        if settings.show_wrap_guides {
17293            match self.soft_wrap_mode(cx) {
17294                SoftWrap::Column(soft_wrap) => {
17295                    wrap_guides.push((soft_wrap as usize, true));
17296                }
17297                SoftWrap::Bounded(soft_wrap) => {
17298                    wrap_guides.push((soft_wrap as usize, true));
17299                }
17300                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17301            }
17302            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17303        }
17304
17305        wrap_guides
17306    }
17307
17308    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17309        let settings = self.buffer.read(cx).language_settings(cx);
17310        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17311        match mode {
17312            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17313                SoftWrap::None
17314            }
17315            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17316            language_settings::SoftWrap::PreferredLineLength => {
17317                SoftWrap::Column(settings.preferred_line_length)
17318            }
17319            language_settings::SoftWrap::Bounded => {
17320                SoftWrap::Bounded(settings.preferred_line_length)
17321            }
17322        }
17323    }
17324
17325    pub fn set_soft_wrap_mode(
17326        &mut self,
17327        mode: language_settings::SoftWrap,
17328
17329        cx: &mut Context<Self>,
17330    ) {
17331        self.soft_wrap_mode_override = Some(mode);
17332        cx.notify();
17333    }
17334
17335    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17336        self.hard_wrap = hard_wrap;
17337        cx.notify();
17338    }
17339
17340    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17341        self.text_style_refinement = Some(style);
17342    }
17343
17344    /// called by the Element so we know what style we were most recently rendered with.
17345    pub(crate) fn set_style(
17346        &mut self,
17347        style: EditorStyle,
17348        window: &mut Window,
17349        cx: &mut Context<Self>,
17350    ) {
17351        // We intentionally do not inform the display map about the minimap style
17352        // so that wrapping is not recalculated and stays consistent for the editor
17353        // and its linked minimap.
17354        if !self.mode.is_minimap() {
17355            let rem_size = window.rem_size();
17356            self.display_map.update(cx, |map, cx| {
17357                map.set_font(
17358                    style.text.font(),
17359                    style.text.font_size.to_pixels(rem_size),
17360                    cx,
17361                )
17362            });
17363        }
17364        self.style = Some(style);
17365    }
17366
17367    pub fn style(&self) -> Option<&EditorStyle> {
17368        self.style.as_ref()
17369    }
17370
17371    // Called by the element. This method is not designed to be called outside of the editor
17372    // element's layout code because it does not notify when rewrapping is computed synchronously.
17373    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17374        self.display_map
17375            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17376    }
17377
17378    pub fn set_soft_wrap(&mut self) {
17379        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17380    }
17381
17382    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17383        if self.soft_wrap_mode_override.is_some() {
17384            self.soft_wrap_mode_override.take();
17385        } else {
17386            let soft_wrap = match self.soft_wrap_mode(cx) {
17387                SoftWrap::GitDiff => return,
17388                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17389                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17390                    language_settings::SoftWrap::None
17391                }
17392            };
17393            self.soft_wrap_mode_override = Some(soft_wrap);
17394        }
17395        cx.notify();
17396    }
17397
17398    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17399        let Some(workspace) = self.workspace() else {
17400            return;
17401        };
17402        let fs = workspace.read(cx).app_state().fs.clone();
17403        let current_show = TabBarSettings::get_global(cx).show;
17404        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17405            setting.show = Some(!current_show);
17406        });
17407    }
17408
17409    pub fn toggle_indent_guides(
17410        &mut self,
17411        _: &ToggleIndentGuides,
17412        _: &mut Window,
17413        cx: &mut Context<Self>,
17414    ) {
17415        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17416            self.buffer
17417                .read(cx)
17418                .language_settings(cx)
17419                .indent_guides
17420                .enabled
17421        });
17422        self.show_indent_guides = Some(!currently_enabled);
17423        cx.notify();
17424    }
17425
17426    fn should_show_indent_guides(&self) -> Option<bool> {
17427        self.show_indent_guides
17428    }
17429
17430    pub fn toggle_line_numbers(
17431        &mut self,
17432        _: &ToggleLineNumbers,
17433        _: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) {
17436        let mut editor_settings = EditorSettings::get_global(cx).clone();
17437        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17438        EditorSettings::override_global(editor_settings, cx);
17439    }
17440
17441    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17442        if let Some(show_line_numbers) = self.show_line_numbers {
17443            return show_line_numbers;
17444        }
17445        EditorSettings::get_global(cx).gutter.line_numbers
17446    }
17447
17448    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17449        self.use_relative_line_numbers
17450            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17451    }
17452
17453    pub fn toggle_relative_line_numbers(
17454        &mut self,
17455        _: &ToggleRelativeLineNumbers,
17456        _: &mut Window,
17457        cx: &mut Context<Self>,
17458    ) {
17459        let is_relative = self.should_use_relative_line_numbers(cx);
17460        self.set_relative_line_number(Some(!is_relative), cx)
17461    }
17462
17463    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17464        self.use_relative_line_numbers = is_relative;
17465        cx.notify();
17466    }
17467
17468    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17469        self.show_gutter = show_gutter;
17470        cx.notify();
17471    }
17472
17473    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17474        self.show_scrollbars = ScrollbarAxes {
17475            horizontal: show,
17476            vertical: show,
17477        };
17478        cx.notify();
17479    }
17480
17481    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17482        self.show_scrollbars.vertical = show;
17483        cx.notify();
17484    }
17485
17486    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17487        self.show_scrollbars.horizontal = show;
17488        cx.notify();
17489    }
17490
17491    pub fn set_minimap_visibility(
17492        &mut self,
17493        minimap_visibility: MinimapVisibility,
17494        window: &mut Window,
17495        cx: &mut Context<Self>,
17496    ) {
17497        if self.minimap_visibility != minimap_visibility {
17498            if minimap_visibility.visible() && self.minimap.is_none() {
17499                let minimap_settings = EditorSettings::get_global(cx).minimap;
17500                self.minimap =
17501                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17502            }
17503            self.minimap_visibility = minimap_visibility;
17504            cx.notify();
17505        }
17506    }
17507
17508    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17509        self.set_show_scrollbars(false, cx);
17510        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17511    }
17512
17513    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17514        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17515    }
17516
17517    /// Normally the text in full mode and auto height editors is padded on the
17518    /// left side by roughly half a character width for improved hit testing.
17519    ///
17520    /// Use this method to disable this for cases where this is not wanted (e.g.
17521    /// if you want to align the editor text with some other text above or below)
17522    /// or if you want to add this padding to single-line editors.
17523    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17524        self.offset_content = offset_content;
17525        cx.notify();
17526    }
17527
17528    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17529        self.show_line_numbers = Some(show_line_numbers);
17530        cx.notify();
17531    }
17532
17533    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17534        self.disable_expand_excerpt_buttons = true;
17535        cx.notify();
17536    }
17537
17538    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17539        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17540        cx.notify();
17541    }
17542
17543    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17544        self.show_code_actions = Some(show_code_actions);
17545        cx.notify();
17546    }
17547
17548    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17549        self.show_runnables = Some(show_runnables);
17550        cx.notify();
17551    }
17552
17553    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17554        self.show_breakpoints = Some(show_breakpoints);
17555        cx.notify();
17556    }
17557
17558    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17559        if self.display_map.read(cx).masked != masked {
17560            self.display_map.update(cx, |map, _| map.masked = masked);
17561        }
17562        cx.notify()
17563    }
17564
17565    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17566        self.show_wrap_guides = Some(show_wrap_guides);
17567        cx.notify();
17568    }
17569
17570    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17571        self.show_indent_guides = Some(show_indent_guides);
17572        cx.notify();
17573    }
17574
17575    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17576        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17577            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17578                if let Some(dir) = file.abs_path(cx).parent() {
17579                    return Some(dir.to_owned());
17580                }
17581            }
17582
17583            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17584                return Some(project_path.path.to_path_buf());
17585            }
17586        }
17587
17588        None
17589    }
17590
17591    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17592        self.active_excerpt(cx)?
17593            .1
17594            .read(cx)
17595            .file()
17596            .and_then(|f| f.as_local())
17597    }
17598
17599    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17600        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17601            let buffer = buffer.read(cx);
17602            if let Some(project_path) = buffer.project_path(cx) {
17603                let project = self.project.as_ref()?.read(cx);
17604                project.absolute_path(&project_path, cx)
17605            } else {
17606                buffer
17607                    .file()
17608                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17609            }
17610        })
17611    }
17612
17613    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17614        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17615            let project_path = buffer.read(cx).project_path(cx)?;
17616            let project = self.project.as_ref()?.read(cx);
17617            let entry = project.entry_for_path(&project_path, cx)?;
17618            let path = entry.path.to_path_buf();
17619            Some(path)
17620        })
17621    }
17622
17623    pub fn reveal_in_finder(
17624        &mut self,
17625        _: &RevealInFileManager,
17626        _window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        if let Some(target) = self.target_file(cx) {
17630            cx.reveal_path(&target.abs_path(cx));
17631        }
17632    }
17633
17634    pub fn copy_path(
17635        &mut self,
17636        _: &zed_actions::workspace::CopyPath,
17637        _window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) {
17640        if let Some(path) = self.target_file_abs_path(cx) {
17641            if let Some(path) = path.to_str() {
17642                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17643            }
17644        }
17645    }
17646
17647    pub fn copy_relative_path(
17648        &mut self,
17649        _: &zed_actions::workspace::CopyRelativePath,
17650        _window: &mut Window,
17651        cx: &mut Context<Self>,
17652    ) {
17653        if let Some(path) = self.target_file_path(cx) {
17654            if let Some(path) = path.to_str() {
17655                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17656            }
17657        }
17658    }
17659
17660    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17661        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17662            buffer.read(cx).project_path(cx)
17663        } else {
17664            None
17665        }
17666    }
17667
17668    // Returns true if the editor handled a go-to-line request
17669    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17670        maybe!({
17671            let breakpoint_store = self.breakpoint_store.as_ref()?;
17672
17673            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17674            else {
17675                self.clear_row_highlights::<ActiveDebugLine>();
17676                return None;
17677            };
17678
17679            let position = active_stack_frame.position;
17680            let buffer_id = position.buffer_id?;
17681            let snapshot = self
17682                .project
17683                .as_ref()?
17684                .read(cx)
17685                .buffer_for_id(buffer_id, cx)?
17686                .read(cx)
17687                .snapshot();
17688
17689            let mut handled = false;
17690            for (id, ExcerptRange { context, .. }) in
17691                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17692            {
17693                if context.start.cmp(&position, &snapshot).is_ge()
17694                    || context.end.cmp(&position, &snapshot).is_lt()
17695                {
17696                    continue;
17697                }
17698                let snapshot = self.buffer.read(cx).snapshot(cx);
17699                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17700
17701                handled = true;
17702                self.clear_row_highlights::<ActiveDebugLine>();
17703
17704                self.go_to_line::<ActiveDebugLine>(
17705                    multibuffer_anchor,
17706                    Some(cx.theme().colors().editor_debugger_active_line_background),
17707                    window,
17708                    cx,
17709                );
17710
17711                cx.notify();
17712            }
17713
17714            handled.then_some(())
17715        })
17716        .is_some()
17717    }
17718
17719    pub fn copy_file_name_without_extension(
17720        &mut self,
17721        _: &CopyFileNameWithoutExtension,
17722        _: &mut Window,
17723        cx: &mut Context<Self>,
17724    ) {
17725        if let Some(file) = self.target_file(cx) {
17726            if let Some(file_stem) = file.path().file_stem() {
17727                if let Some(name) = file_stem.to_str() {
17728                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17729                }
17730            }
17731        }
17732    }
17733
17734    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17735        if let Some(file) = self.target_file(cx) {
17736            if let Some(file_name) = file.path().file_name() {
17737                if let Some(name) = file_name.to_str() {
17738                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17739                }
17740            }
17741        }
17742    }
17743
17744    pub fn toggle_git_blame(
17745        &mut self,
17746        _: &::git::Blame,
17747        window: &mut Window,
17748        cx: &mut Context<Self>,
17749    ) {
17750        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17751
17752        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17753            self.start_git_blame(true, window, cx);
17754        }
17755
17756        cx.notify();
17757    }
17758
17759    pub fn toggle_git_blame_inline(
17760        &mut self,
17761        _: &ToggleGitBlameInline,
17762        window: &mut Window,
17763        cx: &mut Context<Self>,
17764    ) {
17765        self.toggle_git_blame_inline_internal(true, window, cx);
17766        cx.notify();
17767    }
17768
17769    pub fn open_git_blame_commit(
17770        &mut self,
17771        _: &OpenGitBlameCommit,
17772        window: &mut Window,
17773        cx: &mut Context<Self>,
17774    ) {
17775        self.open_git_blame_commit_internal(window, cx);
17776    }
17777
17778    fn open_git_blame_commit_internal(
17779        &mut self,
17780        window: &mut Window,
17781        cx: &mut Context<Self>,
17782    ) -> Option<()> {
17783        let blame = self.blame.as_ref()?;
17784        let snapshot = self.snapshot(window, cx);
17785        let cursor = self.selections.newest::<Point>(cx).head();
17786        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17787        let blame_entry = blame
17788            .update(cx, |blame, cx| {
17789                blame
17790                    .blame_for_rows(
17791                        &[RowInfo {
17792                            buffer_id: Some(buffer.remote_id()),
17793                            buffer_row: Some(point.row),
17794                            ..Default::default()
17795                        }],
17796                        cx,
17797                    )
17798                    .next()
17799            })
17800            .flatten()?;
17801        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17802        let repo = blame.read(cx).repository(cx)?;
17803        let workspace = self.workspace()?.downgrade();
17804        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17805        None
17806    }
17807
17808    pub fn git_blame_inline_enabled(&self) -> bool {
17809        self.git_blame_inline_enabled
17810    }
17811
17812    pub fn toggle_selection_menu(
17813        &mut self,
17814        _: &ToggleSelectionMenu,
17815        _: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) {
17818        self.show_selection_menu = self
17819            .show_selection_menu
17820            .map(|show_selections_menu| !show_selections_menu)
17821            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17822
17823        cx.notify();
17824    }
17825
17826    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17827        self.show_selection_menu
17828            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17829    }
17830
17831    fn start_git_blame(
17832        &mut self,
17833        user_triggered: bool,
17834        window: &mut Window,
17835        cx: &mut Context<Self>,
17836    ) {
17837        if let Some(project) = self.project.as_ref() {
17838            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17839                return;
17840            };
17841
17842            if buffer.read(cx).file().is_none() {
17843                return;
17844            }
17845
17846            let focused = self.focus_handle(cx).contains_focused(window, cx);
17847
17848            let project = project.clone();
17849            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17850            self.blame_subscription =
17851                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17852            self.blame = Some(blame);
17853        }
17854    }
17855
17856    fn toggle_git_blame_inline_internal(
17857        &mut self,
17858        user_triggered: bool,
17859        window: &mut Window,
17860        cx: &mut Context<Self>,
17861    ) {
17862        if self.git_blame_inline_enabled {
17863            self.git_blame_inline_enabled = false;
17864            self.show_git_blame_inline = false;
17865            self.show_git_blame_inline_delay_task.take();
17866        } else {
17867            self.git_blame_inline_enabled = true;
17868            self.start_git_blame_inline(user_triggered, window, cx);
17869        }
17870
17871        cx.notify();
17872    }
17873
17874    fn start_git_blame_inline(
17875        &mut self,
17876        user_triggered: bool,
17877        window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        self.start_git_blame(user_triggered, window, cx);
17881
17882        if ProjectSettings::get_global(cx)
17883            .git
17884            .inline_blame_delay()
17885            .is_some()
17886        {
17887            self.start_inline_blame_timer(window, cx);
17888        } else {
17889            self.show_git_blame_inline = true
17890        }
17891    }
17892
17893    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17894        self.blame.as_ref()
17895    }
17896
17897    pub fn show_git_blame_gutter(&self) -> bool {
17898        self.show_git_blame_gutter
17899    }
17900
17901    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17902        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17903    }
17904
17905    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17906        self.show_git_blame_inline
17907            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17908            && !self.newest_selection_head_on_empty_line(cx)
17909            && self.has_blame_entries(cx)
17910    }
17911
17912    fn has_blame_entries(&self, cx: &App) -> bool {
17913        self.blame()
17914            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17915    }
17916
17917    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17918        let cursor_anchor = self.selections.newest_anchor().head();
17919
17920        let snapshot = self.buffer.read(cx).snapshot(cx);
17921        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17922
17923        snapshot.line_len(buffer_row) == 0
17924    }
17925
17926    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17927        let buffer_and_selection = maybe!({
17928            let selection = self.selections.newest::<Point>(cx);
17929            let selection_range = selection.range();
17930
17931            let multi_buffer = self.buffer().read(cx);
17932            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17933            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17934
17935            let (buffer, range, _) = if selection.reversed {
17936                buffer_ranges.first()
17937            } else {
17938                buffer_ranges.last()
17939            }?;
17940
17941            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17942                ..text::ToPoint::to_point(&range.end, &buffer).row;
17943            Some((
17944                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17945                selection,
17946            ))
17947        });
17948
17949        let Some((buffer, selection)) = buffer_and_selection else {
17950            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17951        };
17952
17953        let Some(project) = self.project.as_ref() else {
17954            return Task::ready(Err(anyhow!("editor does not have project")));
17955        };
17956
17957        project.update(cx, |project, cx| {
17958            project.get_permalink_to_line(&buffer, selection, cx)
17959        })
17960    }
17961
17962    pub fn copy_permalink_to_line(
17963        &mut self,
17964        _: &CopyPermalinkToLine,
17965        window: &mut Window,
17966        cx: &mut Context<Self>,
17967    ) {
17968        let permalink_task = self.get_permalink_to_line(cx);
17969        let workspace = self.workspace();
17970
17971        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17972            Ok(permalink) => {
17973                cx.update(|_, cx| {
17974                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17975                })
17976                .ok();
17977            }
17978            Err(err) => {
17979                let message = format!("Failed to copy permalink: {err}");
17980
17981                anyhow::Result::<()>::Err(err).log_err();
17982
17983                if let Some(workspace) = workspace {
17984                    workspace
17985                        .update_in(cx, |workspace, _, cx| {
17986                            struct CopyPermalinkToLine;
17987
17988                            workspace.show_toast(
17989                                Toast::new(
17990                                    NotificationId::unique::<CopyPermalinkToLine>(),
17991                                    message,
17992                                ),
17993                                cx,
17994                            )
17995                        })
17996                        .ok();
17997                }
17998            }
17999        })
18000        .detach();
18001    }
18002
18003    pub fn copy_file_location(
18004        &mut self,
18005        _: &CopyFileLocation,
18006        _: &mut Window,
18007        cx: &mut Context<Self>,
18008    ) {
18009        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18010        if let Some(file) = self.target_file(cx) {
18011            if let Some(path) = file.path().to_str() {
18012                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18013            }
18014        }
18015    }
18016
18017    pub fn open_permalink_to_line(
18018        &mut self,
18019        _: &OpenPermalinkToLine,
18020        window: &mut Window,
18021        cx: &mut Context<Self>,
18022    ) {
18023        let permalink_task = self.get_permalink_to_line(cx);
18024        let workspace = self.workspace();
18025
18026        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18027            Ok(permalink) => {
18028                cx.update(|_, cx| {
18029                    cx.open_url(permalink.as_ref());
18030                })
18031                .ok();
18032            }
18033            Err(err) => {
18034                let message = format!("Failed to open permalink: {err}");
18035
18036                anyhow::Result::<()>::Err(err).log_err();
18037
18038                if let Some(workspace) = workspace {
18039                    workspace
18040                        .update(cx, |workspace, cx| {
18041                            struct OpenPermalinkToLine;
18042
18043                            workspace.show_toast(
18044                                Toast::new(
18045                                    NotificationId::unique::<OpenPermalinkToLine>(),
18046                                    message,
18047                                ),
18048                                cx,
18049                            )
18050                        })
18051                        .ok();
18052                }
18053            }
18054        })
18055        .detach();
18056    }
18057
18058    pub fn insert_uuid_v4(
18059        &mut self,
18060        _: &InsertUuidV4,
18061        window: &mut Window,
18062        cx: &mut Context<Self>,
18063    ) {
18064        self.insert_uuid(UuidVersion::V4, window, cx);
18065    }
18066
18067    pub fn insert_uuid_v7(
18068        &mut self,
18069        _: &InsertUuidV7,
18070        window: &mut Window,
18071        cx: &mut Context<Self>,
18072    ) {
18073        self.insert_uuid(UuidVersion::V7, window, cx);
18074    }
18075
18076    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18077        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18078        self.transact(window, cx, |this, window, cx| {
18079            let edits = this
18080                .selections
18081                .all::<Point>(cx)
18082                .into_iter()
18083                .map(|selection| {
18084                    let uuid = match version {
18085                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18086                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18087                    };
18088
18089                    (selection.range(), uuid.to_string())
18090                });
18091            this.edit(edits, cx);
18092            this.refresh_inline_completion(true, false, window, cx);
18093        });
18094    }
18095
18096    pub fn open_selections_in_multibuffer(
18097        &mut self,
18098        _: &OpenSelectionsInMultibuffer,
18099        window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        let multibuffer = self.buffer.read(cx);
18103
18104        let Some(buffer) = multibuffer.as_singleton() else {
18105            return;
18106        };
18107
18108        let Some(workspace) = self.workspace() else {
18109            return;
18110        };
18111
18112        let locations = self
18113            .selections
18114            .disjoint_anchors()
18115            .iter()
18116            .map(|selection| {
18117                let range = if selection.reversed {
18118                    selection.end.text_anchor..selection.start.text_anchor
18119                } else {
18120                    selection.start.text_anchor..selection.end.text_anchor
18121                };
18122                Location {
18123                    buffer: buffer.clone(),
18124                    range,
18125                }
18126            })
18127            .collect::<Vec<_>>();
18128
18129        let title = multibuffer.title(cx).to_string();
18130
18131        cx.spawn_in(window, async move |_, cx| {
18132            workspace.update_in(cx, |workspace, window, cx| {
18133                Self::open_locations_in_multibuffer(
18134                    workspace,
18135                    locations,
18136                    format!("Selections for '{title}'"),
18137                    false,
18138                    MultibufferSelectionMode::All,
18139                    window,
18140                    cx,
18141                );
18142            })
18143        })
18144        .detach();
18145    }
18146
18147    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18148    /// last highlight added will be used.
18149    ///
18150    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18151    pub fn highlight_rows<T: 'static>(
18152        &mut self,
18153        range: Range<Anchor>,
18154        color: Hsla,
18155        options: RowHighlightOptions,
18156        cx: &mut Context<Self>,
18157    ) {
18158        let snapshot = self.buffer().read(cx).snapshot(cx);
18159        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18160        let ix = row_highlights.binary_search_by(|highlight| {
18161            Ordering::Equal
18162                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18163                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18164        });
18165
18166        if let Err(mut ix) = ix {
18167            let index = post_inc(&mut self.highlight_order);
18168
18169            // If this range intersects with the preceding highlight, then merge it with
18170            // the preceding highlight. Otherwise insert a new highlight.
18171            let mut merged = false;
18172            if ix > 0 {
18173                let prev_highlight = &mut row_highlights[ix - 1];
18174                if prev_highlight
18175                    .range
18176                    .end
18177                    .cmp(&range.start, &snapshot)
18178                    .is_ge()
18179                {
18180                    ix -= 1;
18181                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18182                        prev_highlight.range.end = range.end;
18183                    }
18184                    merged = true;
18185                    prev_highlight.index = index;
18186                    prev_highlight.color = color;
18187                    prev_highlight.options = options;
18188                }
18189            }
18190
18191            if !merged {
18192                row_highlights.insert(
18193                    ix,
18194                    RowHighlight {
18195                        range: range.clone(),
18196                        index,
18197                        color,
18198                        options,
18199                        type_id: TypeId::of::<T>(),
18200                    },
18201                );
18202            }
18203
18204            // If any of the following highlights intersect with this one, merge them.
18205            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18206                let highlight = &row_highlights[ix];
18207                if next_highlight
18208                    .range
18209                    .start
18210                    .cmp(&highlight.range.end, &snapshot)
18211                    .is_le()
18212                {
18213                    if next_highlight
18214                        .range
18215                        .end
18216                        .cmp(&highlight.range.end, &snapshot)
18217                        .is_gt()
18218                    {
18219                        row_highlights[ix].range.end = next_highlight.range.end;
18220                    }
18221                    row_highlights.remove(ix + 1);
18222                } else {
18223                    break;
18224                }
18225            }
18226        }
18227    }
18228
18229    /// Remove any highlighted row ranges of the given type that intersect the
18230    /// given ranges.
18231    pub fn remove_highlighted_rows<T: 'static>(
18232        &mut self,
18233        ranges_to_remove: Vec<Range<Anchor>>,
18234        cx: &mut Context<Self>,
18235    ) {
18236        let snapshot = self.buffer().read(cx).snapshot(cx);
18237        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18238        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18239        row_highlights.retain(|highlight| {
18240            while let Some(range_to_remove) = ranges_to_remove.peek() {
18241                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18242                    Ordering::Less | Ordering::Equal => {
18243                        ranges_to_remove.next();
18244                    }
18245                    Ordering::Greater => {
18246                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18247                            Ordering::Less | Ordering::Equal => {
18248                                return false;
18249                            }
18250                            Ordering::Greater => break,
18251                        }
18252                    }
18253                }
18254            }
18255
18256            true
18257        })
18258    }
18259
18260    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18261    pub fn clear_row_highlights<T: 'static>(&mut self) {
18262        self.highlighted_rows.remove(&TypeId::of::<T>());
18263    }
18264
18265    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18266    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18267        self.highlighted_rows
18268            .get(&TypeId::of::<T>())
18269            .map_or(&[] as &[_], |vec| vec.as_slice())
18270            .iter()
18271            .map(|highlight| (highlight.range.clone(), highlight.color))
18272    }
18273
18274    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18275    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18276    /// Allows to ignore certain kinds of highlights.
18277    pub fn highlighted_display_rows(
18278        &self,
18279        window: &mut Window,
18280        cx: &mut App,
18281    ) -> BTreeMap<DisplayRow, LineHighlight> {
18282        let snapshot = self.snapshot(window, cx);
18283        let mut used_highlight_orders = HashMap::default();
18284        self.highlighted_rows
18285            .iter()
18286            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18287            .fold(
18288                BTreeMap::<DisplayRow, LineHighlight>::new(),
18289                |mut unique_rows, highlight| {
18290                    let start = highlight.range.start.to_display_point(&snapshot);
18291                    let end = highlight.range.end.to_display_point(&snapshot);
18292                    let start_row = start.row().0;
18293                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18294                        && end.column() == 0
18295                    {
18296                        end.row().0.saturating_sub(1)
18297                    } else {
18298                        end.row().0
18299                    };
18300                    for row in start_row..=end_row {
18301                        let used_index =
18302                            used_highlight_orders.entry(row).or_insert(highlight.index);
18303                        if highlight.index >= *used_index {
18304                            *used_index = highlight.index;
18305                            unique_rows.insert(
18306                                DisplayRow(row),
18307                                LineHighlight {
18308                                    include_gutter: highlight.options.include_gutter,
18309                                    border: None,
18310                                    background: highlight.color.into(),
18311                                    type_id: Some(highlight.type_id),
18312                                },
18313                            );
18314                        }
18315                    }
18316                    unique_rows
18317                },
18318            )
18319    }
18320
18321    pub fn highlighted_display_row_for_autoscroll(
18322        &self,
18323        snapshot: &DisplaySnapshot,
18324    ) -> Option<DisplayRow> {
18325        self.highlighted_rows
18326            .values()
18327            .flat_map(|highlighted_rows| highlighted_rows.iter())
18328            .filter_map(|highlight| {
18329                if highlight.options.autoscroll {
18330                    Some(highlight.range.start.to_display_point(snapshot).row())
18331                } else {
18332                    None
18333                }
18334            })
18335            .min()
18336    }
18337
18338    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18339        self.highlight_background::<SearchWithinRange>(
18340            ranges,
18341            |colors| colors.editor_document_highlight_read_background,
18342            cx,
18343        )
18344    }
18345
18346    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18347        self.breadcrumb_header = Some(new_header);
18348    }
18349
18350    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18351        self.clear_background_highlights::<SearchWithinRange>(cx);
18352    }
18353
18354    pub fn highlight_background<T: 'static>(
18355        &mut self,
18356        ranges: &[Range<Anchor>],
18357        color_fetcher: fn(&ThemeColors) -> Hsla,
18358        cx: &mut Context<Self>,
18359    ) {
18360        self.background_highlights
18361            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18362        self.scrollbar_marker_state.dirty = true;
18363        cx.notify();
18364    }
18365
18366    pub fn clear_background_highlights<T: 'static>(
18367        &mut self,
18368        cx: &mut Context<Self>,
18369    ) -> Option<BackgroundHighlight> {
18370        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18371        if !text_highlights.1.is_empty() {
18372            self.scrollbar_marker_state.dirty = true;
18373            cx.notify();
18374        }
18375        Some(text_highlights)
18376    }
18377
18378    pub fn highlight_gutter<T: 'static>(
18379        &mut self,
18380        ranges: &[Range<Anchor>],
18381        color_fetcher: fn(&App) -> Hsla,
18382        cx: &mut Context<Self>,
18383    ) {
18384        self.gutter_highlights
18385            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18386        cx.notify();
18387    }
18388
18389    pub fn clear_gutter_highlights<T: 'static>(
18390        &mut self,
18391        cx: &mut Context<Self>,
18392    ) -> Option<GutterHighlight> {
18393        cx.notify();
18394        self.gutter_highlights.remove(&TypeId::of::<T>())
18395    }
18396
18397    #[cfg(feature = "test-support")]
18398    pub fn all_text_background_highlights(
18399        &self,
18400        window: &mut Window,
18401        cx: &mut Context<Self>,
18402    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18403        let snapshot = self.snapshot(window, cx);
18404        let buffer = &snapshot.buffer_snapshot;
18405        let start = buffer.anchor_before(0);
18406        let end = buffer.anchor_after(buffer.len());
18407        let theme = cx.theme().colors();
18408        self.background_highlights_in_range(start..end, &snapshot, theme)
18409    }
18410
18411    #[cfg(feature = "test-support")]
18412    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18413        let snapshot = self.buffer().read(cx).snapshot(cx);
18414
18415        let highlights = self
18416            .background_highlights
18417            .get(&TypeId::of::<items::BufferSearchHighlights>());
18418
18419        if let Some((_color, ranges)) = highlights {
18420            ranges
18421                .iter()
18422                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18423                .collect_vec()
18424        } else {
18425            vec![]
18426        }
18427    }
18428
18429    fn document_highlights_for_position<'a>(
18430        &'a self,
18431        position: Anchor,
18432        buffer: &'a MultiBufferSnapshot,
18433    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18434        let read_highlights = self
18435            .background_highlights
18436            .get(&TypeId::of::<DocumentHighlightRead>())
18437            .map(|h| &h.1);
18438        let write_highlights = self
18439            .background_highlights
18440            .get(&TypeId::of::<DocumentHighlightWrite>())
18441            .map(|h| &h.1);
18442        let left_position = position.bias_left(buffer);
18443        let right_position = position.bias_right(buffer);
18444        read_highlights
18445            .into_iter()
18446            .chain(write_highlights)
18447            .flat_map(move |ranges| {
18448                let start_ix = match ranges.binary_search_by(|probe| {
18449                    let cmp = probe.end.cmp(&left_position, buffer);
18450                    if cmp.is_ge() {
18451                        Ordering::Greater
18452                    } else {
18453                        Ordering::Less
18454                    }
18455                }) {
18456                    Ok(i) | Err(i) => i,
18457                };
18458
18459                ranges[start_ix..]
18460                    .iter()
18461                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18462            })
18463    }
18464
18465    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18466        self.background_highlights
18467            .get(&TypeId::of::<T>())
18468            .map_or(false, |(_, highlights)| !highlights.is_empty())
18469    }
18470
18471    pub fn background_highlights_in_range(
18472        &self,
18473        search_range: Range<Anchor>,
18474        display_snapshot: &DisplaySnapshot,
18475        theme: &ThemeColors,
18476    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18477        let mut results = Vec::new();
18478        for (color_fetcher, ranges) in self.background_highlights.values() {
18479            let color = color_fetcher(theme);
18480            let start_ix = match ranges.binary_search_by(|probe| {
18481                let cmp = probe
18482                    .end
18483                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18484                if cmp.is_gt() {
18485                    Ordering::Greater
18486                } else {
18487                    Ordering::Less
18488                }
18489            }) {
18490                Ok(i) | Err(i) => i,
18491            };
18492            for range in &ranges[start_ix..] {
18493                if range
18494                    .start
18495                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18496                    .is_ge()
18497                {
18498                    break;
18499                }
18500
18501                let start = range.start.to_display_point(display_snapshot);
18502                let end = range.end.to_display_point(display_snapshot);
18503                results.push((start..end, color))
18504            }
18505        }
18506        results
18507    }
18508
18509    pub fn background_highlight_row_ranges<T: 'static>(
18510        &self,
18511        search_range: Range<Anchor>,
18512        display_snapshot: &DisplaySnapshot,
18513        count: usize,
18514    ) -> Vec<RangeInclusive<DisplayPoint>> {
18515        let mut results = Vec::new();
18516        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18517            return vec![];
18518        };
18519
18520        let start_ix = match ranges.binary_search_by(|probe| {
18521            let cmp = probe
18522                .end
18523                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18524            if cmp.is_gt() {
18525                Ordering::Greater
18526            } else {
18527                Ordering::Less
18528            }
18529        }) {
18530            Ok(i) | Err(i) => i,
18531        };
18532        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18533            if let (Some(start_display), Some(end_display)) = (start, end) {
18534                results.push(
18535                    start_display.to_display_point(display_snapshot)
18536                        ..=end_display.to_display_point(display_snapshot),
18537                );
18538            }
18539        };
18540        let mut start_row: Option<Point> = None;
18541        let mut end_row: Option<Point> = None;
18542        if ranges.len() > count {
18543            return Vec::new();
18544        }
18545        for range in &ranges[start_ix..] {
18546            if range
18547                .start
18548                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18549                .is_ge()
18550            {
18551                break;
18552            }
18553            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18554            if let Some(current_row) = &end_row {
18555                if end.row == current_row.row {
18556                    continue;
18557                }
18558            }
18559            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18560            if start_row.is_none() {
18561                assert_eq!(end_row, None);
18562                start_row = Some(start);
18563                end_row = Some(end);
18564                continue;
18565            }
18566            if let Some(current_end) = end_row.as_mut() {
18567                if start.row > current_end.row + 1 {
18568                    push_region(start_row, end_row);
18569                    start_row = Some(start);
18570                    end_row = Some(end);
18571                } else {
18572                    // Merge two hunks.
18573                    *current_end = end;
18574                }
18575            } else {
18576                unreachable!();
18577            }
18578        }
18579        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18580        push_region(start_row, end_row);
18581        results
18582    }
18583
18584    pub fn gutter_highlights_in_range(
18585        &self,
18586        search_range: Range<Anchor>,
18587        display_snapshot: &DisplaySnapshot,
18588        cx: &App,
18589    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18590        let mut results = Vec::new();
18591        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18592            let color = color_fetcher(cx);
18593            let start_ix = match ranges.binary_search_by(|probe| {
18594                let cmp = probe
18595                    .end
18596                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18597                if cmp.is_gt() {
18598                    Ordering::Greater
18599                } else {
18600                    Ordering::Less
18601                }
18602            }) {
18603                Ok(i) | Err(i) => i,
18604            };
18605            for range in &ranges[start_ix..] {
18606                if range
18607                    .start
18608                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18609                    .is_ge()
18610                {
18611                    break;
18612                }
18613
18614                let start = range.start.to_display_point(display_snapshot);
18615                let end = range.end.to_display_point(display_snapshot);
18616                results.push((start..end, color))
18617            }
18618        }
18619        results
18620    }
18621
18622    /// Get the text ranges corresponding to the redaction query
18623    pub fn redacted_ranges(
18624        &self,
18625        search_range: Range<Anchor>,
18626        display_snapshot: &DisplaySnapshot,
18627        cx: &App,
18628    ) -> Vec<Range<DisplayPoint>> {
18629        display_snapshot
18630            .buffer_snapshot
18631            .redacted_ranges(search_range, |file| {
18632                if let Some(file) = file {
18633                    file.is_private()
18634                        && EditorSettings::get(
18635                            Some(SettingsLocation {
18636                                worktree_id: file.worktree_id(cx),
18637                                path: file.path().as_ref(),
18638                            }),
18639                            cx,
18640                        )
18641                        .redact_private_values
18642                } else {
18643                    false
18644                }
18645            })
18646            .map(|range| {
18647                range.start.to_display_point(display_snapshot)
18648                    ..range.end.to_display_point(display_snapshot)
18649            })
18650            .collect()
18651    }
18652
18653    pub fn highlight_text<T: 'static>(
18654        &mut self,
18655        ranges: Vec<Range<Anchor>>,
18656        style: HighlightStyle,
18657        cx: &mut Context<Self>,
18658    ) {
18659        self.display_map.update(cx, |map, _| {
18660            map.highlight_text(TypeId::of::<T>(), ranges, style)
18661        });
18662        cx.notify();
18663    }
18664
18665    pub(crate) fn highlight_inlays<T: 'static>(
18666        &mut self,
18667        highlights: Vec<InlayHighlight>,
18668        style: HighlightStyle,
18669        cx: &mut Context<Self>,
18670    ) {
18671        self.display_map.update(cx, |map, _| {
18672            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18673        });
18674        cx.notify();
18675    }
18676
18677    pub fn text_highlights<'a, T: 'static>(
18678        &'a self,
18679        cx: &'a App,
18680    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18681        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18682    }
18683
18684    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18685        let cleared = self
18686            .display_map
18687            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18688        if cleared {
18689            cx.notify();
18690        }
18691    }
18692
18693    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18694        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18695            && self.focus_handle.is_focused(window)
18696    }
18697
18698    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18699        self.show_cursor_when_unfocused = is_enabled;
18700        cx.notify();
18701    }
18702
18703    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18704        cx.notify();
18705    }
18706
18707    fn on_debug_session_event(
18708        &mut self,
18709        _session: Entity<Session>,
18710        event: &SessionEvent,
18711        cx: &mut Context<Self>,
18712    ) {
18713        match event {
18714            SessionEvent::InvalidateInlineValue => {
18715                self.refresh_inline_values(cx);
18716            }
18717            _ => {}
18718        }
18719    }
18720
18721    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18722        let Some(project) = self.project.clone() else {
18723            return;
18724        };
18725
18726        if !self.inline_value_cache.enabled {
18727            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18728            self.splice_inlays(&inlays, Vec::new(), cx);
18729            return;
18730        }
18731
18732        let current_execution_position = self
18733            .highlighted_rows
18734            .get(&TypeId::of::<ActiveDebugLine>())
18735            .and_then(|lines| lines.last().map(|line| line.range.start));
18736
18737        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18738            let inline_values = editor
18739                .update(cx, |editor, cx| {
18740                    let Some(current_execution_position) = current_execution_position else {
18741                        return Some(Task::ready(Ok(Vec::new())));
18742                    };
18743
18744                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18745                        let snapshot = buffer.snapshot(cx);
18746
18747                        let excerpt = snapshot.excerpt_containing(
18748                            current_execution_position..current_execution_position,
18749                        )?;
18750
18751                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18752                    })?;
18753
18754                    let range =
18755                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18756
18757                    project.inline_values(buffer, range, cx)
18758                })
18759                .ok()
18760                .flatten()?
18761                .await
18762                .context("refreshing debugger inlays")
18763                .log_err()?;
18764
18765            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18766
18767            for (buffer_id, inline_value) in inline_values
18768                .into_iter()
18769                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18770            {
18771                buffer_inline_values
18772                    .entry(buffer_id)
18773                    .or_default()
18774                    .push(inline_value);
18775            }
18776
18777            editor
18778                .update(cx, |editor, cx| {
18779                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18780                    let mut new_inlays = Vec::default();
18781
18782                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18783                        let buffer_id = buffer_snapshot.remote_id();
18784                        buffer_inline_values
18785                            .get(&buffer_id)
18786                            .into_iter()
18787                            .flatten()
18788                            .for_each(|hint| {
18789                                let inlay = Inlay::debugger_hint(
18790                                    post_inc(&mut editor.next_inlay_id),
18791                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18792                                    hint.text(),
18793                                );
18794
18795                                new_inlays.push(inlay);
18796                            });
18797                    }
18798
18799                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18800                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18801
18802                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18803                })
18804                .ok()?;
18805            Some(())
18806        });
18807    }
18808
18809    fn on_buffer_event(
18810        &mut self,
18811        multibuffer: &Entity<MultiBuffer>,
18812        event: &multi_buffer::Event,
18813        window: &mut Window,
18814        cx: &mut Context<Self>,
18815    ) {
18816        match event {
18817            multi_buffer::Event::Edited {
18818                singleton_buffer_edited,
18819                edited_buffer,
18820            } => {
18821                self.scrollbar_marker_state.dirty = true;
18822                self.active_indent_guides_state.dirty = true;
18823                self.refresh_active_diagnostics(cx);
18824                self.refresh_code_actions(window, cx);
18825                self.refresh_selected_text_highlights(true, window, cx);
18826                refresh_matching_bracket_highlights(self, window, cx);
18827                if self.has_active_inline_completion() {
18828                    self.update_visible_inline_completion(window, cx);
18829                }
18830                if let Some(project) = self.project.as_ref() {
18831                    if let Some(edited_buffer) = edited_buffer {
18832                        project.update(cx, |project, cx| {
18833                            self.registered_buffers
18834                                .entry(edited_buffer.read(cx).remote_id())
18835                                .or_insert_with(|| {
18836                                    project
18837                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18838                                });
18839                        });
18840                        if edited_buffer.read(cx).file().is_some() {
18841                            self.pull_diagnostics(
18842                                Some(edited_buffer.read(cx).remote_id()),
18843                                window,
18844                                cx,
18845                            );
18846                        }
18847                    }
18848                }
18849                cx.emit(EditorEvent::BufferEdited);
18850                cx.emit(SearchEvent::MatchesInvalidated);
18851                if *singleton_buffer_edited {
18852                    if let Some(buffer) = edited_buffer {
18853                        if buffer.read(cx).file().is_none() {
18854                            cx.emit(EditorEvent::TitleChanged);
18855                        }
18856                    }
18857                    if let Some(project) = &self.project {
18858                        #[allow(clippy::mutable_key_type)]
18859                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18860                            multibuffer
18861                                .all_buffers()
18862                                .into_iter()
18863                                .filter_map(|buffer| {
18864                                    buffer.update(cx, |buffer, cx| {
18865                                        let language = buffer.language()?;
18866                                        let should_discard = project.update(cx, |project, cx| {
18867                                            project.is_local()
18868                                                && !project.has_language_servers_for(buffer, cx)
18869                                        });
18870                                        should_discard.not().then_some(language.clone())
18871                                    })
18872                                })
18873                                .collect::<HashSet<_>>()
18874                        });
18875                        if !languages_affected.is_empty() {
18876                            self.refresh_inlay_hints(
18877                                InlayHintRefreshReason::BufferEdited(languages_affected),
18878                                cx,
18879                            );
18880                        }
18881                    }
18882                }
18883
18884                let Some(project) = &self.project else { return };
18885                let (telemetry, is_via_ssh) = {
18886                    let project = project.read(cx);
18887                    let telemetry = project.client().telemetry().clone();
18888                    let is_via_ssh = project.is_via_ssh();
18889                    (telemetry, is_via_ssh)
18890                };
18891                refresh_linked_ranges(self, window, cx);
18892                telemetry.log_edit_event("editor", is_via_ssh);
18893            }
18894            multi_buffer::Event::ExcerptsAdded {
18895                buffer,
18896                predecessor,
18897                excerpts,
18898            } => {
18899                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18900                let buffer_id = buffer.read(cx).remote_id();
18901                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18902                    if let Some(project) = &self.project {
18903                        update_uncommitted_diff_for_buffer(
18904                            cx.entity(),
18905                            project,
18906                            [buffer.clone()],
18907                            self.buffer.clone(),
18908                            cx,
18909                        )
18910                        .detach();
18911                    }
18912                }
18913                cx.emit(EditorEvent::ExcerptsAdded {
18914                    buffer: buffer.clone(),
18915                    predecessor: *predecessor,
18916                    excerpts: excerpts.clone(),
18917                });
18918                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18919            }
18920            multi_buffer::Event::ExcerptsRemoved {
18921                ids,
18922                removed_buffer_ids,
18923            } => {
18924                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18925                let buffer = self.buffer.read(cx);
18926                self.registered_buffers
18927                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18928                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18929                cx.emit(EditorEvent::ExcerptsRemoved {
18930                    ids: ids.clone(),
18931                    removed_buffer_ids: removed_buffer_ids.clone(),
18932                })
18933            }
18934            multi_buffer::Event::ExcerptsEdited {
18935                excerpt_ids,
18936                buffer_ids,
18937            } => {
18938                self.display_map.update(cx, |map, cx| {
18939                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18940                });
18941                cx.emit(EditorEvent::ExcerptsEdited {
18942                    ids: excerpt_ids.clone(),
18943                })
18944            }
18945            multi_buffer::Event::ExcerptsExpanded { ids } => {
18946                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18947                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18948            }
18949            multi_buffer::Event::Reparsed(buffer_id) => {
18950                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18951                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18952
18953                cx.emit(EditorEvent::Reparsed(*buffer_id));
18954            }
18955            multi_buffer::Event::DiffHunksToggled => {
18956                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18957            }
18958            multi_buffer::Event::LanguageChanged(buffer_id) => {
18959                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18960                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18961                cx.emit(EditorEvent::Reparsed(*buffer_id));
18962                cx.notify();
18963            }
18964            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18965            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18966            multi_buffer::Event::FileHandleChanged
18967            | multi_buffer::Event::Reloaded
18968            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18969            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18970            multi_buffer::Event::DiagnosticsUpdated => {
18971                self.update_diagnostics_state(window, cx);
18972            }
18973            _ => {}
18974        };
18975    }
18976
18977    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
18978        self.refresh_active_diagnostics(cx);
18979        self.refresh_inline_diagnostics(true, window, cx);
18980        self.scrollbar_marker_state.dirty = true;
18981        cx.notify();
18982    }
18983
18984    pub fn start_temporary_diff_override(&mut self) {
18985        self.load_diff_task.take();
18986        self.temporary_diff_override = true;
18987    }
18988
18989    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18990        self.temporary_diff_override = false;
18991        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18992        self.buffer.update(cx, |buffer, cx| {
18993            buffer.set_all_diff_hunks_collapsed(cx);
18994        });
18995
18996        if let Some(project) = self.project.clone() {
18997            self.load_diff_task = Some(
18998                update_uncommitted_diff_for_buffer(
18999                    cx.entity(),
19000                    &project,
19001                    self.buffer.read(cx).all_buffers(),
19002                    self.buffer.clone(),
19003                    cx,
19004                )
19005                .shared(),
19006            );
19007        }
19008    }
19009
19010    fn on_display_map_changed(
19011        &mut self,
19012        _: Entity<DisplayMap>,
19013        _: &mut Window,
19014        cx: &mut Context<Self>,
19015    ) {
19016        cx.notify();
19017    }
19018
19019    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19020        let new_severity = if self.diagnostics_enabled() {
19021            EditorSettings::get_global(cx)
19022                .diagnostics_max_severity
19023                .unwrap_or(DiagnosticSeverity::Hint)
19024        } else {
19025            DiagnosticSeverity::Off
19026        };
19027        self.set_max_diagnostics_severity(new_severity, cx);
19028        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19029        self.update_edit_prediction_settings(cx);
19030        self.refresh_inline_completion(true, false, window, cx);
19031        self.refresh_inlay_hints(
19032            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19033                self.selections.newest_anchor().head(),
19034                &self.buffer.read(cx).snapshot(cx),
19035                cx,
19036            )),
19037            cx,
19038        );
19039
19040        let old_cursor_shape = self.cursor_shape;
19041
19042        {
19043            let editor_settings = EditorSettings::get_global(cx);
19044            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19045            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19046            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19047            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19048            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19049        }
19050
19051        if old_cursor_shape != self.cursor_shape {
19052            cx.emit(EditorEvent::CursorShapeChanged);
19053        }
19054
19055        let project_settings = ProjectSettings::get_global(cx);
19056        self.serialize_dirty_buffers =
19057            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19058
19059        if self.mode.is_full() {
19060            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19061            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19062            if self.show_inline_diagnostics != show_inline_diagnostics {
19063                self.show_inline_diagnostics = show_inline_diagnostics;
19064                self.refresh_inline_diagnostics(false, window, cx);
19065            }
19066
19067            if self.git_blame_inline_enabled != inline_blame_enabled {
19068                self.toggle_git_blame_inline_internal(false, window, cx);
19069            }
19070
19071            let minimap_settings = EditorSettings::get_global(cx).minimap;
19072            if self.minimap_visibility != MinimapVisibility::Disabled {
19073                if self.minimap_visibility.settings_visibility()
19074                    != minimap_settings.minimap_enabled()
19075                {
19076                    self.set_minimap_visibility(
19077                        MinimapVisibility::for_mode(self.mode(), cx),
19078                        window,
19079                        cx,
19080                    );
19081                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19082                    minimap_entity.update(cx, |minimap_editor, cx| {
19083                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19084                    })
19085                }
19086            }
19087        }
19088
19089        cx.notify();
19090    }
19091
19092    pub fn set_searchable(&mut self, searchable: bool) {
19093        self.searchable = searchable;
19094    }
19095
19096    pub fn searchable(&self) -> bool {
19097        self.searchable
19098    }
19099
19100    fn open_proposed_changes_editor(
19101        &mut self,
19102        _: &OpenProposedChangesEditor,
19103        window: &mut Window,
19104        cx: &mut Context<Self>,
19105    ) {
19106        let Some(workspace) = self.workspace() else {
19107            cx.propagate();
19108            return;
19109        };
19110
19111        let selections = self.selections.all::<usize>(cx);
19112        let multi_buffer = self.buffer.read(cx);
19113        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19114        let mut new_selections_by_buffer = HashMap::default();
19115        for selection in selections {
19116            for (buffer, range, _) in
19117                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19118            {
19119                let mut range = range.to_point(buffer);
19120                range.start.column = 0;
19121                range.end.column = buffer.line_len(range.end.row);
19122                new_selections_by_buffer
19123                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19124                    .or_insert(Vec::new())
19125                    .push(range)
19126            }
19127        }
19128
19129        let proposed_changes_buffers = new_selections_by_buffer
19130            .into_iter()
19131            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19132            .collect::<Vec<_>>();
19133        let proposed_changes_editor = cx.new(|cx| {
19134            ProposedChangesEditor::new(
19135                "Proposed changes",
19136                proposed_changes_buffers,
19137                self.project.clone(),
19138                window,
19139                cx,
19140            )
19141        });
19142
19143        window.defer(cx, move |window, cx| {
19144            workspace.update(cx, |workspace, cx| {
19145                workspace.active_pane().update(cx, |pane, cx| {
19146                    pane.add_item(
19147                        Box::new(proposed_changes_editor),
19148                        true,
19149                        true,
19150                        None,
19151                        window,
19152                        cx,
19153                    );
19154                });
19155            });
19156        });
19157    }
19158
19159    pub fn open_excerpts_in_split(
19160        &mut self,
19161        _: &OpenExcerptsSplit,
19162        window: &mut Window,
19163        cx: &mut Context<Self>,
19164    ) {
19165        self.open_excerpts_common(None, true, window, cx)
19166    }
19167
19168    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19169        self.open_excerpts_common(None, false, window, cx)
19170    }
19171
19172    fn open_excerpts_common(
19173        &mut self,
19174        jump_data: Option<JumpData>,
19175        split: bool,
19176        window: &mut Window,
19177        cx: &mut Context<Self>,
19178    ) {
19179        let Some(workspace) = self.workspace() else {
19180            cx.propagate();
19181            return;
19182        };
19183
19184        if self.buffer.read(cx).is_singleton() {
19185            cx.propagate();
19186            return;
19187        }
19188
19189        let mut new_selections_by_buffer = HashMap::default();
19190        match &jump_data {
19191            Some(JumpData::MultiBufferPoint {
19192                excerpt_id,
19193                position,
19194                anchor,
19195                line_offset_from_top,
19196            }) => {
19197                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19198                if let Some(buffer) = multi_buffer_snapshot
19199                    .buffer_id_for_excerpt(*excerpt_id)
19200                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19201                {
19202                    let buffer_snapshot = buffer.read(cx).snapshot();
19203                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19204                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19205                    } else {
19206                        buffer_snapshot.clip_point(*position, Bias::Left)
19207                    };
19208                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19209                    new_selections_by_buffer.insert(
19210                        buffer,
19211                        (
19212                            vec![jump_to_offset..jump_to_offset],
19213                            Some(*line_offset_from_top),
19214                        ),
19215                    );
19216                }
19217            }
19218            Some(JumpData::MultiBufferRow {
19219                row,
19220                line_offset_from_top,
19221            }) => {
19222                let point = MultiBufferPoint::new(row.0, 0);
19223                if let Some((buffer, buffer_point, _)) =
19224                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19225                {
19226                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19227                    new_selections_by_buffer
19228                        .entry(buffer)
19229                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19230                        .0
19231                        .push(buffer_offset..buffer_offset)
19232                }
19233            }
19234            None => {
19235                let selections = self.selections.all::<usize>(cx);
19236                let multi_buffer = self.buffer.read(cx);
19237                for selection in selections {
19238                    for (snapshot, range, _, anchor) in multi_buffer
19239                        .snapshot(cx)
19240                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19241                    {
19242                        if let Some(anchor) = anchor {
19243                            // selection is in a deleted hunk
19244                            let Some(buffer_id) = anchor.buffer_id else {
19245                                continue;
19246                            };
19247                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19248                                continue;
19249                            };
19250                            let offset = text::ToOffset::to_offset(
19251                                &anchor.text_anchor,
19252                                &buffer_handle.read(cx).snapshot(),
19253                            );
19254                            let range = offset..offset;
19255                            new_selections_by_buffer
19256                                .entry(buffer_handle)
19257                                .or_insert((Vec::new(), None))
19258                                .0
19259                                .push(range)
19260                        } else {
19261                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19262                            else {
19263                                continue;
19264                            };
19265                            new_selections_by_buffer
19266                                .entry(buffer_handle)
19267                                .or_insert((Vec::new(), None))
19268                                .0
19269                                .push(range)
19270                        }
19271                    }
19272                }
19273            }
19274        }
19275
19276        new_selections_by_buffer
19277            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19278
19279        if new_selections_by_buffer.is_empty() {
19280            return;
19281        }
19282
19283        // We defer the pane interaction because we ourselves are a workspace item
19284        // and activating a new item causes the pane to call a method on us reentrantly,
19285        // which panics if we're on the stack.
19286        window.defer(cx, move |window, cx| {
19287            workspace.update(cx, |workspace, cx| {
19288                let pane = if split {
19289                    workspace.adjacent_pane(window, cx)
19290                } else {
19291                    workspace.active_pane().clone()
19292                };
19293
19294                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19295                    let editor = buffer
19296                        .read(cx)
19297                        .file()
19298                        .is_none()
19299                        .then(|| {
19300                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19301                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19302                            // Instead, we try to activate the existing editor in the pane first.
19303                            let (editor, pane_item_index) =
19304                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19305                                    let editor = item.downcast::<Editor>()?;
19306                                    let singleton_buffer =
19307                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19308                                    if singleton_buffer == buffer {
19309                                        Some((editor, i))
19310                                    } else {
19311                                        None
19312                                    }
19313                                })?;
19314                            pane.update(cx, |pane, cx| {
19315                                pane.activate_item(pane_item_index, true, true, window, cx)
19316                            });
19317                            Some(editor)
19318                        })
19319                        .flatten()
19320                        .unwrap_or_else(|| {
19321                            workspace.open_project_item::<Self>(
19322                                pane.clone(),
19323                                buffer,
19324                                true,
19325                                true,
19326                                window,
19327                                cx,
19328                            )
19329                        });
19330
19331                    editor.update(cx, |editor, cx| {
19332                        let autoscroll = match scroll_offset {
19333                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19334                            None => Autoscroll::newest(),
19335                        };
19336                        let nav_history = editor.nav_history.take();
19337                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19338                            s.select_ranges(ranges);
19339                        });
19340                        editor.nav_history = nav_history;
19341                    });
19342                }
19343            })
19344        });
19345    }
19346
19347    // For now, don't allow opening excerpts in buffers that aren't backed by
19348    // regular project files.
19349    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19350        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19351    }
19352
19353    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19354        let snapshot = self.buffer.read(cx).read(cx);
19355        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19356        Some(
19357            ranges
19358                .iter()
19359                .map(move |range| {
19360                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19361                })
19362                .collect(),
19363        )
19364    }
19365
19366    fn selection_replacement_ranges(
19367        &self,
19368        range: Range<OffsetUtf16>,
19369        cx: &mut App,
19370    ) -> Vec<Range<OffsetUtf16>> {
19371        let selections = self.selections.all::<OffsetUtf16>(cx);
19372        let newest_selection = selections
19373            .iter()
19374            .max_by_key(|selection| selection.id)
19375            .unwrap();
19376        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19377        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19378        let snapshot = self.buffer.read(cx).read(cx);
19379        selections
19380            .into_iter()
19381            .map(|mut selection| {
19382                selection.start.0 =
19383                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19384                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19385                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19386                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19387            })
19388            .collect()
19389    }
19390
19391    fn report_editor_event(
19392        &self,
19393        event_type: &'static str,
19394        file_extension: Option<String>,
19395        cx: &App,
19396    ) {
19397        if cfg!(any(test, feature = "test-support")) {
19398            return;
19399        }
19400
19401        let Some(project) = &self.project else { return };
19402
19403        // If None, we are in a file without an extension
19404        let file = self
19405            .buffer
19406            .read(cx)
19407            .as_singleton()
19408            .and_then(|b| b.read(cx).file());
19409        let file_extension = file_extension.or(file
19410            .as_ref()
19411            .and_then(|file| Path::new(file.file_name(cx)).extension())
19412            .and_then(|e| e.to_str())
19413            .map(|a| a.to_string()));
19414
19415        let vim_mode = vim_enabled(cx);
19416
19417        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19418        let copilot_enabled = edit_predictions_provider
19419            == language::language_settings::EditPredictionProvider::Copilot;
19420        let copilot_enabled_for_language = self
19421            .buffer
19422            .read(cx)
19423            .language_settings(cx)
19424            .show_edit_predictions;
19425
19426        let project = project.read(cx);
19427        telemetry::event!(
19428            event_type,
19429            file_extension,
19430            vim_mode,
19431            copilot_enabled,
19432            copilot_enabled_for_language,
19433            edit_predictions_provider,
19434            is_via_ssh = project.is_via_ssh(),
19435        );
19436    }
19437
19438    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19439    /// with each line being an array of {text, highlight} objects.
19440    fn copy_highlight_json(
19441        &mut self,
19442        _: &CopyHighlightJson,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) {
19446        #[derive(Serialize)]
19447        struct Chunk<'a> {
19448            text: String,
19449            highlight: Option<&'a str>,
19450        }
19451
19452        let snapshot = self.buffer.read(cx).snapshot(cx);
19453        let range = self
19454            .selected_text_range(false, window, cx)
19455            .and_then(|selection| {
19456                if selection.range.is_empty() {
19457                    None
19458                } else {
19459                    Some(selection.range)
19460                }
19461            })
19462            .unwrap_or_else(|| 0..snapshot.len());
19463
19464        let chunks = snapshot.chunks(range, true);
19465        let mut lines = Vec::new();
19466        let mut line: VecDeque<Chunk> = VecDeque::new();
19467
19468        let Some(style) = self.style.as_ref() else {
19469            return;
19470        };
19471
19472        for chunk in chunks {
19473            let highlight = chunk
19474                .syntax_highlight_id
19475                .and_then(|id| id.name(&style.syntax));
19476            let mut chunk_lines = chunk.text.split('\n').peekable();
19477            while let Some(text) = chunk_lines.next() {
19478                let mut merged_with_last_token = false;
19479                if let Some(last_token) = line.back_mut() {
19480                    if last_token.highlight == highlight {
19481                        last_token.text.push_str(text);
19482                        merged_with_last_token = true;
19483                    }
19484                }
19485
19486                if !merged_with_last_token {
19487                    line.push_back(Chunk {
19488                        text: text.into(),
19489                        highlight,
19490                    });
19491                }
19492
19493                if chunk_lines.peek().is_some() {
19494                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19495                        line.pop_front();
19496                    }
19497                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19498                        line.pop_back();
19499                    }
19500
19501                    lines.push(mem::take(&mut line));
19502                }
19503            }
19504        }
19505
19506        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19507            return;
19508        };
19509        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19510    }
19511
19512    pub fn open_context_menu(
19513        &mut self,
19514        _: &OpenContextMenu,
19515        window: &mut Window,
19516        cx: &mut Context<Self>,
19517    ) {
19518        self.request_autoscroll(Autoscroll::newest(), cx);
19519        let position = self.selections.newest_display(cx).start;
19520        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19521    }
19522
19523    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19524        &self.inlay_hint_cache
19525    }
19526
19527    pub fn replay_insert_event(
19528        &mut self,
19529        text: &str,
19530        relative_utf16_range: Option<Range<isize>>,
19531        window: &mut Window,
19532        cx: &mut Context<Self>,
19533    ) {
19534        if !self.input_enabled {
19535            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19536            return;
19537        }
19538        if let Some(relative_utf16_range) = relative_utf16_range {
19539            let selections = self.selections.all::<OffsetUtf16>(cx);
19540            self.change_selections(None, window, cx, |s| {
19541                let new_ranges = selections.into_iter().map(|range| {
19542                    let start = OffsetUtf16(
19543                        range
19544                            .head()
19545                            .0
19546                            .saturating_add_signed(relative_utf16_range.start),
19547                    );
19548                    let end = OffsetUtf16(
19549                        range
19550                            .head()
19551                            .0
19552                            .saturating_add_signed(relative_utf16_range.end),
19553                    );
19554                    start..end
19555                });
19556                s.select_ranges(new_ranges);
19557            });
19558        }
19559
19560        self.handle_input(text, window, cx);
19561    }
19562
19563    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19564        let Some(provider) = self.semantics_provider.as_ref() else {
19565            return false;
19566        };
19567
19568        let mut supports = false;
19569        self.buffer().update(cx, |this, cx| {
19570            this.for_each_buffer(|buffer| {
19571                supports |= provider.supports_inlay_hints(buffer, cx);
19572            });
19573        });
19574
19575        supports
19576    }
19577
19578    pub fn is_focused(&self, window: &Window) -> bool {
19579        self.focus_handle.is_focused(window)
19580    }
19581
19582    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19583        cx.emit(EditorEvent::Focused);
19584
19585        if let Some(descendant) = self
19586            .last_focused_descendant
19587            .take()
19588            .and_then(|descendant| descendant.upgrade())
19589        {
19590            window.focus(&descendant);
19591        } else {
19592            if let Some(blame) = self.blame.as_ref() {
19593                blame.update(cx, GitBlame::focus)
19594            }
19595
19596            self.blink_manager.update(cx, BlinkManager::enable);
19597            self.show_cursor_names(window, cx);
19598            self.buffer.update(cx, |buffer, cx| {
19599                buffer.finalize_last_transaction(cx);
19600                if self.leader_id.is_none() {
19601                    buffer.set_active_selections(
19602                        &self.selections.disjoint_anchors(),
19603                        self.selections.line_mode,
19604                        self.cursor_shape,
19605                        cx,
19606                    );
19607                }
19608            });
19609        }
19610    }
19611
19612    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19613        cx.emit(EditorEvent::FocusedIn)
19614    }
19615
19616    fn handle_focus_out(
19617        &mut self,
19618        event: FocusOutEvent,
19619        _window: &mut Window,
19620        cx: &mut Context<Self>,
19621    ) {
19622        if event.blurred != self.focus_handle {
19623            self.last_focused_descendant = Some(event.blurred);
19624        }
19625        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19626    }
19627
19628    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19629        self.blink_manager.update(cx, BlinkManager::disable);
19630        self.buffer
19631            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19632
19633        if let Some(blame) = self.blame.as_ref() {
19634            blame.update(cx, GitBlame::blur)
19635        }
19636        if !self.hover_state.focused(window, cx) {
19637            hide_hover(self, cx);
19638        }
19639        if !self
19640            .context_menu
19641            .borrow()
19642            .as_ref()
19643            .is_some_and(|context_menu| context_menu.focused(window, cx))
19644        {
19645            self.hide_context_menu(window, cx);
19646        }
19647        self.discard_inline_completion(false, cx);
19648        cx.emit(EditorEvent::Blurred);
19649        cx.notify();
19650    }
19651
19652    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19653        let mut pending: String = window
19654            .pending_input_keystrokes()
19655            .into_iter()
19656            .flatten()
19657            .filter_map(|keystroke| {
19658                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19659                    Some(keystroke.key_char.clone().unwrap_or(keystroke.key.clone()))
19660                } else {
19661                    None
19662                }
19663            })
19664            .collect();
19665
19666        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19667            pending = "".to_string();
19668        }
19669
19670        let existing_pending = self
19671            .text_highlights::<PendingInput>(cx)
19672            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19673        if existing_pending.is_none() && pending.is_empty() {
19674            return;
19675        }
19676        let transaction =
19677            self.transact(window, cx, |this, window, cx| {
19678                let selections = this.selections.all::<usize>(cx);
19679                let edits = selections
19680                    .iter()
19681                    .map(|selection| (selection.end..selection.end, pending.clone()));
19682                this.edit(edits, cx);
19683                this.change_selections(None, window, cx, |s| {
19684                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19685                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19686                    }));
19687                });
19688                if let Some(existing_ranges) = existing_pending {
19689                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19690                    this.edit(edits, cx);
19691                }
19692            });
19693
19694        let snapshot = self.snapshot(window, cx);
19695        let ranges = self
19696            .selections
19697            .all::<usize>(cx)
19698            .into_iter()
19699            .map(|selection| {
19700                snapshot.buffer_snapshot.anchor_after(selection.end)
19701                    ..snapshot
19702                        .buffer_snapshot
19703                        .anchor_before(selection.end + pending.len())
19704            })
19705            .collect();
19706
19707        if pending.is_empty() {
19708            self.clear_highlights::<PendingInput>(cx);
19709        } else {
19710            self.highlight_text::<PendingInput>(
19711                ranges,
19712                HighlightStyle {
19713                    underline: Some(UnderlineStyle {
19714                        thickness: px(1.),
19715                        color: None,
19716                        wavy: false,
19717                    }),
19718                    ..Default::default()
19719                },
19720                cx,
19721            );
19722        }
19723
19724        self.ime_transaction = self.ime_transaction.or(transaction);
19725        if let Some(transaction) = self.ime_transaction {
19726            self.buffer.update(cx, |buffer, cx| {
19727                buffer.group_until_transaction(transaction, cx);
19728            });
19729        }
19730
19731        if self.text_highlights::<PendingInput>(cx).is_none() {
19732            self.ime_transaction.take();
19733        }
19734    }
19735
19736    pub fn register_action<A: Action>(
19737        &mut self,
19738        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19739    ) -> Subscription {
19740        let id = self.next_editor_action_id.post_inc();
19741        let listener = Arc::new(listener);
19742        self.editor_actions.borrow_mut().insert(
19743            id,
19744            Box::new(move |window, _| {
19745                let listener = listener.clone();
19746                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19747                    let action = action.downcast_ref().unwrap();
19748                    if phase == DispatchPhase::Bubble {
19749                        listener(action, window, cx)
19750                    }
19751                })
19752            }),
19753        );
19754
19755        let editor_actions = self.editor_actions.clone();
19756        Subscription::new(move || {
19757            editor_actions.borrow_mut().remove(&id);
19758        })
19759    }
19760
19761    pub fn file_header_size(&self) -> u32 {
19762        FILE_HEADER_HEIGHT
19763    }
19764
19765    pub fn restore(
19766        &mut self,
19767        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19768        window: &mut Window,
19769        cx: &mut Context<Self>,
19770    ) {
19771        let workspace = self.workspace();
19772        let project = self.project.as_ref();
19773        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19774            let mut tasks = Vec::new();
19775            for (buffer_id, changes) in revert_changes {
19776                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19777                    buffer.update(cx, |buffer, cx| {
19778                        buffer.edit(
19779                            changes
19780                                .into_iter()
19781                                .map(|(range, text)| (range, text.to_string())),
19782                            None,
19783                            cx,
19784                        );
19785                    });
19786
19787                    if let Some(project) =
19788                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19789                    {
19790                        project.update(cx, |project, cx| {
19791                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19792                        })
19793                    }
19794                }
19795            }
19796            tasks
19797        });
19798        cx.spawn_in(window, async move |_, cx| {
19799            for (buffer, task) in save_tasks {
19800                let result = task.await;
19801                if result.is_err() {
19802                    let Some(path) = buffer
19803                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19804                        .ok()
19805                    else {
19806                        continue;
19807                    };
19808                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19809                        let Some(task) = cx
19810                            .update_window_entity(&workspace, |workspace, window, cx| {
19811                                workspace
19812                                    .open_path_preview(path, None, false, false, false, window, cx)
19813                            })
19814                            .ok()
19815                        else {
19816                            continue;
19817                        };
19818                        task.await.log_err();
19819                    }
19820                }
19821            }
19822        })
19823        .detach();
19824        self.change_selections(None, window, cx, |selections| selections.refresh());
19825    }
19826
19827    pub fn to_pixel_point(
19828        &self,
19829        source: multi_buffer::Anchor,
19830        editor_snapshot: &EditorSnapshot,
19831        window: &mut Window,
19832    ) -> Option<gpui::Point<Pixels>> {
19833        let source_point = source.to_display_point(editor_snapshot);
19834        self.display_to_pixel_point(source_point, editor_snapshot, window)
19835    }
19836
19837    pub fn display_to_pixel_point(
19838        &self,
19839        source: DisplayPoint,
19840        editor_snapshot: &EditorSnapshot,
19841        window: &mut Window,
19842    ) -> Option<gpui::Point<Pixels>> {
19843        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19844        let text_layout_details = self.text_layout_details(window);
19845        let scroll_top = text_layout_details
19846            .scroll_anchor
19847            .scroll_position(editor_snapshot)
19848            .y;
19849
19850        if source.row().as_f32() < scroll_top.floor() {
19851            return None;
19852        }
19853        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19854        let source_y = line_height * (source.row().as_f32() - scroll_top);
19855        Some(gpui::Point::new(source_x, source_y))
19856    }
19857
19858    pub fn has_visible_completions_menu(&self) -> bool {
19859        !self.edit_prediction_preview_is_active()
19860            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19861                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19862            })
19863    }
19864
19865    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19866        if self.mode.is_minimap() {
19867            return;
19868        }
19869        self.addons
19870            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19871    }
19872
19873    pub fn unregister_addon<T: Addon>(&mut self) {
19874        self.addons.remove(&std::any::TypeId::of::<T>());
19875    }
19876
19877    pub fn addon<T: Addon>(&self) -> Option<&T> {
19878        let type_id = std::any::TypeId::of::<T>();
19879        self.addons
19880            .get(&type_id)
19881            .and_then(|item| item.to_any().downcast_ref::<T>())
19882    }
19883
19884    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19885        let type_id = std::any::TypeId::of::<T>();
19886        self.addons
19887            .get_mut(&type_id)
19888            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19889    }
19890
19891    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19892        let text_layout_details = self.text_layout_details(window);
19893        let style = &text_layout_details.editor_style;
19894        let font_id = window.text_system().resolve_font(&style.text.font());
19895        let font_size = style.text.font_size.to_pixels(window.rem_size());
19896        let line_height = style.text.line_height_in_pixels(window.rem_size());
19897        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19898
19899        gpui::Size::new(em_width, line_height)
19900    }
19901
19902    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19903        self.load_diff_task.clone()
19904    }
19905
19906    fn read_metadata_from_db(
19907        &mut self,
19908        item_id: u64,
19909        workspace_id: WorkspaceId,
19910        window: &mut Window,
19911        cx: &mut Context<Editor>,
19912    ) {
19913        if self.is_singleton(cx)
19914            && !self.mode.is_minimap()
19915            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19916        {
19917            let buffer_snapshot = OnceCell::new();
19918
19919            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19920                if !folds.is_empty() {
19921                    let snapshot =
19922                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19923                    self.fold_ranges(
19924                        folds
19925                            .into_iter()
19926                            .map(|(start, end)| {
19927                                snapshot.clip_offset(start, Bias::Left)
19928                                    ..snapshot.clip_offset(end, Bias::Right)
19929                            })
19930                            .collect(),
19931                        false,
19932                        window,
19933                        cx,
19934                    );
19935                }
19936            }
19937
19938            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19939                if !selections.is_empty() {
19940                    let snapshot =
19941                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19942                    self.change_selections(None, window, cx, |s| {
19943                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19944                            snapshot.clip_offset(start, Bias::Left)
19945                                ..snapshot.clip_offset(end, Bias::Right)
19946                        }));
19947                    });
19948                }
19949            };
19950        }
19951
19952        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19953    }
19954}
19955
19956fn vim_enabled(cx: &App) -> bool {
19957    cx.global::<SettingsStore>()
19958        .raw_user_settings()
19959        .get("vim_mode")
19960        == Some(&serde_json::Value::Bool(true))
19961}
19962
19963fn process_completion_for_edit(
19964    completion: &Completion,
19965    intent: CompletionIntent,
19966    buffer: &Entity<Buffer>,
19967    cursor_position: &text::Anchor,
19968    cx: &mut Context<Editor>,
19969) -> CompletionEdit {
19970    let buffer = buffer.read(cx);
19971    let buffer_snapshot = buffer.snapshot();
19972    let (snippet, new_text) = if completion.is_snippet() {
19973        let mut snippet_source = completion.new_text.clone();
19974        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19975            if scope.prefers_label_for_snippet_in_completion() {
19976                if let Some(label) = completion.label() {
19977                    if matches!(
19978                        completion.kind(),
19979                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19980                    ) {
19981                        snippet_source = label;
19982                    }
19983                }
19984            }
19985        }
19986        match Snippet::parse(&snippet_source).log_err() {
19987            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19988            None => (None, completion.new_text.clone()),
19989        }
19990    } else {
19991        (None, completion.new_text.clone())
19992    };
19993
19994    let mut range_to_replace = {
19995        let replace_range = &completion.replace_range;
19996        if let CompletionSource::Lsp {
19997            insert_range: Some(insert_range),
19998            ..
19999        } = &completion.source
20000        {
20001            debug_assert_eq!(
20002                insert_range.start, replace_range.start,
20003                "insert_range and replace_range should start at the same position"
20004            );
20005            debug_assert!(
20006                insert_range
20007                    .start
20008                    .cmp(&cursor_position, &buffer_snapshot)
20009                    .is_le(),
20010                "insert_range should start before or at cursor position"
20011            );
20012            debug_assert!(
20013                replace_range
20014                    .start
20015                    .cmp(&cursor_position, &buffer_snapshot)
20016                    .is_le(),
20017                "replace_range should start before or at cursor position"
20018            );
20019            debug_assert!(
20020                insert_range
20021                    .end
20022                    .cmp(&cursor_position, &buffer_snapshot)
20023                    .is_le(),
20024                "insert_range should end before or at cursor position"
20025            );
20026
20027            let should_replace = match intent {
20028                CompletionIntent::CompleteWithInsert => false,
20029                CompletionIntent::CompleteWithReplace => true,
20030                CompletionIntent::Complete | CompletionIntent::Compose => {
20031                    let insert_mode =
20032                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20033                            .completions
20034                            .lsp_insert_mode;
20035                    match insert_mode {
20036                        LspInsertMode::Insert => false,
20037                        LspInsertMode::Replace => true,
20038                        LspInsertMode::ReplaceSubsequence => {
20039                            let mut text_to_replace = buffer.chars_for_range(
20040                                buffer.anchor_before(replace_range.start)
20041                                    ..buffer.anchor_after(replace_range.end),
20042                            );
20043                            let mut current_needle = text_to_replace.next();
20044                            for haystack_ch in completion.label.text.chars() {
20045                                if let Some(needle_ch) = current_needle {
20046                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20047                                        current_needle = text_to_replace.next();
20048                                    }
20049                                }
20050                            }
20051                            current_needle.is_none()
20052                        }
20053                        LspInsertMode::ReplaceSuffix => {
20054                            if replace_range
20055                                .end
20056                                .cmp(&cursor_position, &buffer_snapshot)
20057                                .is_gt()
20058                            {
20059                                let range_after_cursor = *cursor_position..replace_range.end;
20060                                let text_after_cursor = buffer
20061                                    .text_for_range(
20062                                        buffer.anchor_before(range_after_cursor.start)
20063                                            ..buffer.anchor_after(range_after_cursor.end),
20064                                    )
20065                                    .collect::<String>()
20066                                    .to_ascii_lowercase();
20067                                completion
20068                                    .label
20069                                    .text
20070                                    .to_ascii_lowercase()
20071                                    .ends_with(&text_after_cursor)
20072                            } else {
20073                                true
20074                            }
20075                        }
20076                    }
20077                }
20078            };
20079
20080            if should_replace {
20081                replace_range.clone()
20082            } else {
20083                insert_range.clone()
20084            }
20085        } else {
20086            replace_range.clone()
20087        }
20088    };
20089
20090    if range_to_replace
20091        .end
20092        .cmp(&cursor_position, &buffer_snapshot)
20093        .is_lt()
20094    {
20095        range_to_replace.end = *cursor_position;
20096    }
20097
20098    CompletionEdit {
20099        new_text,
20100        replace_range: range_to_replace.to_offset(&buffer),
20101        snippet,
20102    }
20103}
20104
20105struct CompletionEdit {
20106    new_text: String,
20107    replace_range: Range<usize>,
20108    snippet: Option<Snippet>,
20109}
20110
20111fn insert_extra_newline_brackets(
20112    buffer: &MultiBufferSnapshot,
20113    range: Range<usize>,
20114    language: &language::LanguageScope,
20115) -> bool {
20116    let leading_whitespace_len = buffer
20117        .reversed_chars_at(range.start)
20118        .take_while(|c| c.is_whitespace() && *c != '\n')
20119        .map(|c| c.len_utf8())
20120        .sum::<usize>();
20121    let trailing_whitespace_len = buffer
20122        .chars_at(range.end)
20123        .take_while(|c| c.is_whitespace() && *c != '\n')
20124        .map(|c| c.len_utf8())
20125        .sum::<usize>();
20126    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20127
20128    language.brackets().any(|(pair, enabled)| {
20129        let pair_start = pair.start.trim_end();
20130        let pair_end = pair.end.trim_start();
20131
20132        enabled
20133            && pair.newline
20134            && buffer.contains_str_at(range.end, pair_end)
20135            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20136    })
20137}
20138
20139fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20140    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20141        [(buffer, range, _)] => (*buffer, range.clone()),
20142        _ => return false,
20143    };
20144    let pair = {
20145        let mut result: Option<BracketMatch> = None;
20146
20147        for pair in buffer
20148            .all_bracket_ranges(range.clone())
20149            .filter(move |pair| {
20150                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20151            })
20152        {
20153            let len = pair.close_range.end - pair.open_range.start;
20154
20155            if let Some(existing) = &result {
20156                let existing_len = existing.close_range.end - existing.open_range.start;
20157                if len > existing_len {
20158                    continue;
20159                }
20160            }
20161
20162            result = Some(pair);
20163        }
20164
20165        result
20166    };
20167    let Some(pair) = pair else {
20168        return false;
20169    };
20170    pair.newline_only
20171        && buffer
20172            .chars_for_range(pair.open_range.end..range.start)
20173            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20174            .all(|c| c.is_whitespace() && c != '\n')
20175}
20176
20177fn update_uncommitted_diff_for_buffer(
20178    editor: Entity<Editor>,
20179    project: &Entity<Project>,
20180    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20181    buffer: Entity<MultiBuffer>,
20182    cx: &mut App,
20183) -> Task<()> {
20184    let mut tasks = Vec::new();
20185    project.update(cx, |project, cx| {
20186        for buffer in buffers {
20187            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20188                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20189            }
20190        }
20191    });
20192    cx.spawn(async move |cx| {
20193        let diffs = future::join_all(tasks).await;
20194        if editor
20195            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20196            .unwrap_or(false)
20197        {
20198            return;
20199        }
20200
20201        buffer
20202            .update(cx, |buffer, cx| {
20203                for diff in diffs.into_iter().flatten() {
20204                    buffer.add_diff(diff, cx);
20205                }
20206            })
20207            .ok();
20208    })
20209}
20210
20211fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20212    let tab_size = tab_size.get() as usize;
20213    let mut width = offset;
20214
20215    for ch in text.chars() {
20216        width += if ch == '\t' {
20217            tab_size - (width % tab_size)
20218        } else {
20219            1
20220        };
20221    }
20222
20223    width - offset
20224}
20225
20226#[cfg(test)]
20227mod tests {
20228    use super::*;
20229
20230    #[test]
20231    fn test_string_size_with_expanded_tabs() {
20232        let nz = |val| NonZeroU32::new(val).unwrap();
20233        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20234        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20235        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20236        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20237        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20238        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20239        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20240        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20241    }
20242}
20243
20244/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20245struct WordBreakingTokenizer<'a> {
20246    input: &'a str,
20247}
20248
20249impl<'a> WordBreakingTokenizer<'a> {
20250    fn new(input: &'a str) -> Self {
20251        Self { input }
20252    }
20253}
20254
20255fn is_char_ideographic(ch: char) -> bool {
20256    use unicode_script::Script::*;
20257    use unicode_script::UnicodeScript;
20258    matches!(ch.script(), Han | Tangut | Yi)
20259}
20260
20261fn is_grapheme_ideographic(text: &str) -> bool {
20262    text.chars().any(is_char_ideographic)
20263}
20264
20265fn is_grapheme_whitespace(text: &str) -> bool {
20266    text.chars().any(|x| x.is_whitespace())
20267}
20268
20269fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20270    text.chars().next().map_or(false, |ch| {
20271        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20272    })
20273}
20274
20275#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20276enum WordBreakToken<'a> {
20277    Word { token: &'a str, grapheme_len: usize },
20278    InlineWhitespace { token: &'a str, grapheme_len: usize },
20279    Newline,
20280}
20281
20282impl<'a> Iterator for WordBreakingTokenizer<'a> {
20283    /// Yields a span, the count of graphemes in the token, and whether it was
20284    /// whitespace. Note that it also breaks at word boundaries.
20285    type Item = WordBreakToken<'a>;
20286
20287    fn next(&mut self) -> Option<Self::Item> {
20288        use unicode_segmentation::UnicodeSegmentation;
20289        if self.input.is_empty() {
20290            return None;
20291        }
20292
20293        let mut iter = self.input.graphemes(true).peekable();
20294        let mut offset = 0;
20295        let mut grapheme_len = 0;
20296        if let Some(first_grapheme) = iter.next() {
20297            let is_newline = first_grapheme == "\n";
20298            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20299            offset += first_grapheme.len();
20300            grapheme_len += 1;
20301            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20302                if let Some(grapheme) = iter.peek().copied() {
20303                    if should_stay_with_preceding_ideograph(grapheme) {
20304                        offset += grapheme.len();
20305                        grapheme_len += 1;
20306                    }
20307                }
20308            } else {
20309                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20310                let mut next_word_bound = words.peek().copied();
20311                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20312                    next_word_bound = words.next();
20313                }
20314                while let Some(grapheme) = iter.peek().copied() {
20315                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20316                        break;
20317                    };
20318                    if is_grapheme_whitespace(grapheme) != is_whitespace
20319                        || (grapheme == "\n") != is_newline
20320                    {
20321                        break;
20322                    };
20323                    offset += grapheme.len();
20324                    grapheme_len += 1;
20325                    iter.next();
20326                }
20327            }
20328            let token = &self.input[..offset];
20329            self.input = &self.input[offset..];
20330            if token == "\n" {
20331                Some(WordBreakToken::Newline)
20332            } else if is_whitespace {
20333                Some(WordBreakToken::InlineWhitespace {
20334                    token,
20335                    grapheme_len,
20336                })
20337            } else {
20338                Some(WordBreakToken::Word {
20339                    token,
20340                    grapheme_len,
20341                })
20342            }
20343        } else {
20344            None
20345        }
20346    }
20347}
20348
20349#[test]
20350fn test_word_breaking_tokenizer() {
20351    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20352        ("", &[]),
20353        ("  ", &[whitespace("  ", 2)]),
20354        ("Ʒ", &[word("Ʒ", 1)]),
20355        ("Ǽ", &[word("Ǽ", 1)]),
20356        ("", &[word("", 1)]),
20357        ("⋑⋑", &[word("⋑⋑", 2)]),
20358        (
20359            "原理,进而",
20360            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20361        ),
20362        (
20363            "hello world",
20364            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20365        ),
20366        (
20367            "hello, world",
20368            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20369        ),
20370        (
20371            "  hello world",
20372            &[
20373                whitespace("  ", 2),
20374                word("hello", 5),
20375                whitespace(" ", 1),
20376                word("world", 5),
20377            ],
20378        ),
20379        (
20380            "这是什么 \n 钢笔",
20381            &[
20382                word("", 1),
20383                word("", 1),
20384                word("", 1),
20385                word("", 1),
20386                whitespace(" ", 1),
20387                newline(),
20388                whitespace(" ", 1),
20389                word("", 1),
20390                word("", 1),
20391            ],
20392        ),
20393        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20394    ];
20395
20396    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20397        WordBreakToken::Word {
20398            token,
20399            grapheme_len,
20400        }
20401    }
20402
20403    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20404        WordBreakToken::InlineWhitespace {
20405            token,
20406            grapheme_len,
20407        }
20408    }
20409
20410    fn newline() -> WordBreakToken<'static> {
20411        WordBreakToken::Newline
20412    }
20413
20414    for (input, result) in tests {
20415        assert_eq!(
20416            WordBreakingTokenizer::new(input)
20417                .collect::<Vec<_>>()
20418                .as_slice(),
20419            *result,
20420        );
20421    }
20422}
20423
20424fn wrap_with_prefix(
20425    line_prefix: String,
20426    unwrapped_text: String,
20427    wrap_column: usize,
20428    tab_size: NonZeroU32,
20429    preserve_existing_whitespace: bool,
20430) -> String {
20431    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20432    let mut wrapped_text = String::new();
20433    let mut current_line = line_prefix.clone();
20434
20435    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20436    let mut current_line_len = line_prefix_len;
20437    let mut in_whitespace = false;
20438    for token in tokenizer {
20439        let have_preceding_whitespace = in_whitespace;
20440        match token {
20441            WordBreakToken::Word {
20442                token,
20443                grapheme_len,
20444            } => {
20445                in_whitespace = false;
20446                if current_line_len + grapheme_len > wrap_column
20447                    && current_line_len != line_prefix_len
20448                {
20449                    wrapped_text.push_str(current_line.trim_end());
20450                    wrapped_text.push('\n');
20451                    current_line.truncate(line_prefix.len());
20452                    current_line_len = line_prefix_len;
20453                }
20454                current_line.push_str(token);
20455                current_line_len += grapheme_len;
20456            }
20457            WordBreakToken::InlineWhitespace {
20458                mut token,
20459                mut grapheme_len,
20460            } => {
20461                in_whitespace = true;
20462                if have_preceding_whitespace && !preserve_existing_whitespace {
20463                    continue;
20464                }
20465                if !preserve_existing_whitespace {
20466                    token = " ";
20467                    grapheme_len = 1;
20468                }
20469                if current_line_len + grapheme_len > wrap_column {
20470                    wrapped_text.push_str(current_line.trim_end());
20471                    wrapped_text.push('\n');
20472                    current_line.truncate(line_prefix.len());
20473                    current_line_len = line_prefix_len;
20474                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20475                    current_line.push_str(token);
20476                    current_line_len += grapheme_len;
20477                }
20478            }
20479            WordBreakToken::Newline => {
20480                in_whitespace = true;
20481                if preserve_existing_whitespace {
20482                    wrapped_text.push_str(current_line.trim_end());
20483                    wrapped_text.push('\n');
20484                    current_line.truncate(line_prefix.len());
20485                    current_line_len = line_prefix_len;
20486                } else if have_preceding_whitespace {
20487                    continue;
20488                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20489                {
20490                    wrapped_text.push_str(current_line.trim_end());
20491                    wrapped_text.push('\n');
20492                    current_line.truncate(line_prefix.len());
20493                    current_line_len = line_prefix_len;
20494                } else if current_line_len != line_prefix_len {
20495                    current_line.push(' ');
20496                    current_line_len += 1;
20497                }
20498            }
20499        }
20500    }
20501
20502    if !current_line.is_empty() {
20503        wrapped_text.push_str(&current_line);
20504    }
20505    wrapped_text
20506}
20507
20508#[test]
20509fn test_wrap_with_prefix() {
20510    assert_eq!(
20511        wrap_with_prefix(
20512            "# ".to_string(),
20513            "abcdefg".to_string(),
20514            4,
20515            NonZeroU32::new(4).unwrap(),
20516            false,
20517        ),
20518        "# abcdefg"
20519    );
20520    assert_eq!(
20521        wrap_with_prefix(
20522            "".to_string(),
20523            "\thello world".to_string(),
20524            8,
20525            NonZeroU32::new(4).unwrap(),
20526            false,
20527        ),
20528        "hello\nworld"
20529    );
20530    assert_eq!(
20531        wrap_with_prefix(
20532            "// ".to_string(),
20533            "xx \nyy zz aa bb cc".to_string(),
20534            12,
20535            NonZeroU32::new(4).unwrap(),
20536            false,
20537        ),
20538        "// xx yy zz\n// aa bb cc"
20539    );
20540    assert_eq!(
20541        wrap_with_prefix(
20542            String::new(),
20543            "这是什么 \n 钢笔".to_string(),
20544            3,
20545            NonZeroU32::new(4).unwrap(),
20546            false,
20547        ),
20548        "这是什\n么 钢\n"
20549    );
20550}
20551
20552pub trait CollaborationHub {
20553    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20554    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20555    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20556}
20557
20558impl CollaborationHub for Entity<Project> {
20559    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20560        self.read(cx).collaborators()
20561    }
20562
20563    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20564        self.read(cx).user_store().read(cx).participant_indices()
20565    }
20566
20567    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20568        let this = self.read(cx);
20569        let user_ids = this.collaborators().values().map(|c| c.user_id);
20570        this.user_store().read(cx).participant_names(user_ids, cx)
20571    }
20572}
20573
20574pub trait SemanticsProvider {
20575    fn hover(
20576        &self,
20577        buffer: &Entity<Buffer>,
20578        position: text::Anchor,
20579        cx: &mut App,
20580    ) -> Option<Task<Vec<project::Hover>>>;
20581
20582    fn inline_values(
20583        &self,
20584        buffer_handle: Entity<Buffer>,
20585        range: Range<text::Anchor>,
20586        cx: &mut App,
20587    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20588
20589    fn inlay_hints(
20590        &self,
20591        buffer_handle: Entity<Buffer>,
20592        range: Range<text::Anchor>,
20593        cx: &mut App,
20594    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20595
20596    fn resolve_inlay_hint(
20597        &self,
20598        hint: InlayHint,
20599        buffer_handle: Entity<Buffer>,
20600        server_id: LanguageServerId,
20601        cx: &mut App,
20602    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20603
20604    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20605
20606    fn document_highlights(
20607        &self,
20608        buffer: &Entity<Buffer>,
20609        position: text::Anchor,
20610        cx: &mut App,
20611    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20612
20613    fn definitions(
20614        &self,
20615        buffer: &Entity<Buffer>,
20616        position: text::Anchor,
20617        kind: GotoDefinitionKind,
20618        cx: &mut App,
20619    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20620
20621    fn range_for_rename(
20622        &self,
20623        buffer: &Entity<Buffer>,
20624        position: text::Anchor,
20625        cx: &mut App,
20626    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20627
20628    fn perform_rename(
20629        &self,
20630        buffer: &Entity<Buffer>,
20631        position: text::Anchor,
20632        new_name: String,
20633        cx: &mut App,
20634    ) -> Option<Task<Result<ProjectTransaction>>>;
20635
20636    fn pull_diagnostics_for_buffer(
20637        &self,
20638        buffer: Entity<Buffer>,
20639        cx: &mut App,
20640    ) -> Task<anyhow::Result<()>>;
20641}
20642
20643pub trait CompletionProvider {
20644    fn completions(
20645        &self,
20646        excerpt_id: ExcerptId,
20647        buffer: &Entity<Buffer>,
20648        buffer_position: text::Anchor,
20649        trigger: CompletionContext,
20650        window: &mut Window,
20651        cx: &mut Context<Editor>,
20652    ) -> Task<Result<Vec<CompletionResponse>>>;
20653
20654    fn resolve_completions(
20655        &self,
20656        _buffer: Entity<Buffer>,
20657        _completion_indices: Vec<usize>,
20658        _completions: Rc<RefCell<Box<[Completion]>>>,
20659        _cx: &mut Context<Editor>,
20660    ) -> Task<Result<bool>> {
20661        Task::ready(Ok(false))
20662    }
20663
20664    fn apply_additional_edits_for_completion(
20665        &self,
20666        _buffer: Entity<Buffer>,
20667        _completions: Rc<RefCell<Box<[Completion]>>>,
20668        _completion_index: usize,
20669        _push_to_history: bool,
20670        _cx: &mut Context<Editor>,
20671    ) -> Task<Result<Option<language::Transaction>>> {
20672        Task::ready(Ok(None))
20673    }
20674
20675    fn is_completion_trigger(
20676        &self,
20677        buffer: &Entity<Buffer>,
20678        position: language::Anchor,
20679        text: &str,
20680        trigger_in_words: bool,
20681        menu_is_open: bool,
20682        cx: &mut Context<Editor>,
20683    ) -> bool;
20684
20685    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20686
20687    fn sort_completions(&self) -> bool {
20688        true
20689    }
20690
20691    fn filter_completions(&self) -> bool {
20692        true
20693    }
20694}
20695
20696pub trait CodeActionProvider {
20697    fn id(&self) -> Arc<str>;
20698
20699    fn code_actions(
20700        &self,
20701        buffer: &Entity<Buffer>,
20702        range: Range<text::Anchor>,
20703        window: &mut Window,
20704        cx: &mut App,
20705    ) -> Task<Result<Vec<CodeAction>>>;
20706
20707    fn apply_code_action(
20708        &self,
20709        buffer_handle: Entity<Buffer>,
20710        action: CodeAction,
20711        excerpt_id: ExcerptId,
20712        push_to_history: bool,
20713        window: &mut Window,
20714        cx: &mut App,
20715    ) -> Task<Result<ProjectTransaction>>;
20716}
20717
20718impl CodeActionProvider for Entity<Project> {
20719    fn id(&self) -> Arc<str> {
20720        "project".into()
20721    }
20722
20723    fn code_actions(
20724        &self,
20725        buffer: &Entity<Buffer>,
20726        range: Range<text::Anchor>,
20727        _window: &mut Window,
20728        cx: &mut App,
20729    ) -> Task<Result<Vec<CodeAction>>> {
20730        self.update(cx, |project, cx| {
20731            let code_lens = project.code_lens(buffer, range.clone(), cx);
20732            let code_actions = project.code_actions(buffer, range, None, cx);
20733            cx.background_spawn(async move {
20734                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20735                Ok(code_lens
20736                    .context("code lens fetch")?
20737                    .into_iter()
20738                    .chain(code_actions.context("code action fetch")?)
20739                    .collect())
20740            })
20741        })
20742    }
20743
20744    fn apply_code_action(
20745        &self,
20746        buffer_handle: Entity<Buffer>,
20747        action: CodeAction,
20748        _excerpt_id: ExcerptId,
20749        push_to_history: bool,
20750        _window: &mut Window,
20751        cx: &mut App,
20752    ) -> Task<Result<ProjectTransaction>> {
20753        self.update(cx, |project, cx| {
20754            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20755        })
20756    }
20757}
20758
20759fn snippet_completions(
20760    project: &Project,
20761    buffer: &Entity<Buffer>,
20762    buffer_position: text::Anchor,
20763    cx: &mut App,
20764) -> Task<Result<CompletionResponse>> {
20765    let languages = buffer.read(cx).languages_at(buffer_position);
20766    let snippet_store = project.snippets().read(cx);
20767
20768    let scopes: Vec<_> = languages
20769        .iter()
20770        .filter_map(|language| {
20771            let language_name = language.lsp_id();
20772            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20773
20774            if snippets.is_empty() {
20775                None
20776            } else {
20777                Some((language.default_scope(), snippets))
20778            }
20779        })
20780        .collect();
20781
20782    if scopes.is_empty() {
20783        return Task::ready(Ok(CompletionResponse {
20784            completions: vec![],
20785            is_incomplete: false,
20786        }));
20787    }
20788
20789    let snapshot = buffer.read(cx).text_snapshot();
20790    let chars: String = snapshot
20791        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20792        .collect();
20793    let executor = cx.background_executor().clone();
20794
20795    cx.background_spawn(async move {
20796        let mut is_incomplete = false;
20797        let mut completions: Vec<Completion> = Vec::new();
20798        for (scope, snippets) in scopes.into_iter() {
20799            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20800            let mut last_word = chars
20801                .chars()
20802                .take_while(|c| classifier.is_word(*c))
20803                .collect::<String>();
20804            last_word = last_word.chars().rev().collect();
20805
20806            if last_word.is_empty() {
20807                return Ok(CompletionResponse {
20808                    completions: vec![],
20809                    is_incomplete: true,
20810                });
20811            }
20812
20813            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20814            let to_lsp = |point: &text::Anchor| {
20815                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20816                point_to_lsp(end)
20817            };
20818            let lsp_end = to_lsp(&buffer_position);
20819
20820            let candidates = snippets
20821                .iter()
20822                .enumerate()
20823                .flat_map(|(ix, snippet)| {
20824                    snippet
20825                        .prefix
20826                        .iter()
20827                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20828                })
20829                .collect::<Vec<StringMatchCandidate>>();
20830
20831            const MAX_RESULTS: usize = 100;
20832            let mut matches = fuzzy::match_strings(
20833                &candidates,
20834                &last_word,
20835                last_word.chars().any(|c| c.is_uppercase()),
20836                MAX_RESULTS,
20837                &Default::default(),
20838                executor.clone(),
20839            )
20840            .await;
20841
20842            if matches.len() >= MAX_RESULTS {
20843                is_incomplete = true;
20844            }
20845
20846            // Remove all candidates where the query's start does not match the start of any word in the candidate
20847            if let Some(query_start) = last_word.chars().next() {
20848                matches.retain(|string_match| {
20849                    split_words(&string_match.string).any(|word| {
20850                        // Check that the first codepoint of the word as lowercase matches the first
20851                        // codepoint of the query as lowercase
20852                        word.chars()
20853                            .flat_map(|codepoint| codepoint.to_lowercase())
20854                            .zip(query_start.to_lowercase())
20855                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20856                    })
20857                });
20858            }
20859
20860            let matched_strings = matches
20861                .into_iter()
20862                .map(|m| m.string)
20863                .collect::<HashSet<_>>();
20864
20865            completions.extend(snippets.iter().filter_map(|snippet| {
20866                let matching_prefix = snippet
20867                    .prefix
20868                    .iter()
20869                    .find(|prefix| matched_strings.contains(*prefix))?;
20870                let start = as_offset - last_word.len();
20871                let start = snapshot.anchor_before(start);
20872                let range = start..buffer_position;
20873                let lsp_start = to_lsp(&start);
20874                let lsp_range = lsp::Range {
20875                    start: lsp_start,
20876                    end: lsp_end,
20877                };
20878                Some(Completion {
20879                    replace_range: range,
20880                    new_text: snippet.body.clone(),
20881                    source: CompletionSource::Lsp {
20882                        insert_range: None,
20883                        server_id: LanguageServerId(usize::MAX),
20884                        resolved: true,
20885                        lsp_completion: Box::new(lsp::CompletionItem {
20886                            label: snippet.prefix.first().unwrap().clone(),
20887                            kind: Some(CompletionItemKind::SNIPPET),
20888                            label_details: snippet.description.as_ref().map(|description| {
20889                                lsp::CompletionItemLabelDetails {
20890                                    detail: Some(description.clone()),
20891                                    description: None,
20892                                }
20893                            }),
20894                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20895                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20896                                lsp::InsertReplaceEdit {
20897                                    new_text: snippet.body.clone(),
20898                                    insert: lsp_range,
20899                                    replace: lsp_range,
20900                                },
20901                            )),
20902                            filter_text: Some(snippet.body.clone()),
20903                            sort_text: Some(char::MAX.to_string()),
20904                            ..lsp::CompletionItem::default()
20905                        }),
20906                        lsp_defaults: None,
20907                    },
20908                    label: CodeLabel {
20909                        text: matching_prefix.clone(),
20910                        runs: Vec::new(),
20911                        filter_range: 0..matching_prefix.len(),
20912                    },
20913                    icon_path: None,
20914                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20915                        single_line: snippet.name.clone().into(),
20916                        plain_text: snippet
20917                            .description
20918                            .clone()
20919                            .map(|description| description.into()),
20920                    }),
20921                    insert_text_mode: None,
20922                    confirm: None,
20923                })
20924            }))
20925        }
20926
20927        Ok(CompletionResponse {
20928            completions,
20929            is_incomplete,
20930        })
20931    })
20932}
20933
20934impl CompletionProvider for Entity<Project> {
20935    fn completions(
20936        &self,
20937        _excerpt_id: ExcerptId,
20938        buffer: &Entity<Buffer>,
20939        buffer_position: text::Anchor,
20940        options: CompletionContext,
20941        _window: &mut Window,
20942        cx: &mut Context<Editor>,
20943    ) -> Task<Result<Vec<CompletionResponse>>> {
20944        self.update(cx, |project, cx| {
20945            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20946            let project_completions = project.completions(buffer, buffer_position, options, cx);
20947            cx.background_spawn(async move {
20948                let mut responses = project_completions.await?;
20949                let snippets = snippets.await?;
20950                if !snippets.completions.is_empty() {
20951                    responses.push(snippets);
20952                }
20953                Ok(responses)
20954            })
20955        })
20956    }
20957
20958    fn resolve_completions(
20959        &self,
20960        buffer: Entity<Buffer>,
20961        completion_indices: Vec<usize>,
20962        completions: Rc<RefCell<Box<[Completion]>>>,
20963        cx: &mut Context<Editor>,
20964    ) -> Task<Result<bool>> {
20965        self.update(cx, |project, cx| {
20966            project.lsp_store().update(cx, |lsp_store, cx| {
20967                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20968            })
20969        })
20970    }
20971
20972    fn apply_additional_edits_for_completion(
20973        &self,
20974        buffer: Entity<Buffer>,
20975        completions: Rc<RefCell<Box<[Completion]>>>,
20976        completion_index: usize,
20977        push_to_history: bool,
20978        cx: &mut Context<Editor>,
20979    ) -> Task<Result<Option<language::Transaction>>> {
20980        self.update(cx, |project, cx| {
20981            project.lsp_store().update(cx, |lsp_store, cx| {
20982                lsp_store.apply_additional_edits_for_completion(
20983                    buffer,
20984                    completions,
20985                    completion_index,
20986                    push_to_history,
20987                    cx,
20988                )
20989            })
20990        })
20991    }
20992
20993    fn is_completion_trigger(
20994        &self,
20995        buffer: &Entity<Buffer>,
20996        position: language::Anchor,
20997        text: &str,
20998        trigger_in_words: bool,
20999        menu_is_open: bool,
21000        cx: &mut Context<Editor>,
21001    ) -> bool {
21002        let mut chars = text.chars();
21003        let char = if let Some(char) = chars.next() {
21004            char
21005        } else {
21006            return false;
21007        };
21008        if chars.next().is_some() {
21009            return false;
21010        }
21011
21012        let buffer = buffer.read(cx);
21013        let snapshot = buffer.snapshot();
21014        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21015            return false;
21016        }
21017        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21018        if trigger_in_words && classifier.is_word(char) {
21019            return true;
21020        }
21021
21022        buffer.completion_triggers().contains(text)
21023    }
21024}
21025
21026impl SemanticsProvider for Entity<Project> {
21027    fn hover(
21028        &self,
21029        buffer: &Entity<Buffer>,
21030        position: text::Anchor,
21031        cx: &mut App,
21032    ) -> Option<Task<Vec<project::Hover>>> {
21033        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21034    }
21035
21036    fn document_highlights(
21037        &self,
21038        buffer: &Entity<Buffer>,
21039        position: text::Anchor,
21040        cx: &mut App,
21041    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21042        Some(self.update(cx, |project, cx| {
21043            project.document_highlights(buffer, position, cx)
21044        }))
21045    }
21046
21047    fn definitions(
21048        &self,
21049        buffer: &Entity<Buffer>,
21050        position: text::Anchor,
21051        kind: GotoDefinitionKind,
21052        cx: &mut App,
21053    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21054        Some(self.update(cx, |project, cx| match kind {
21055            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21056            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21057            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21058            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21059        }))
21060    }
21061
21062    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21063        // TODO: make this work for remote projects
21064        self.update(cx, |project, cx| {
21065            if project
21066                .active_debug_session(cx)
21067                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21068            {
21069                return true;
21070            }
21071
21072            buffer.update(cx, |buffer, cx| {
21073                project.any_language_server_supports_inlay_hints(buffer, cx)
21074            })
21075        })
21076    }
21077
21078    fn inline_values(
21079        &self,
21080        buffer_handle: Entity<Buffer>,
21081
21082        range: Range<text::Anchor>,
21083        cx: &mut App,
21084    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21085        self.update(cx, |project, cx| {
21086            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21087
21088            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21089        })
21090    }
21091
21092    fn inlay_hints(
21093        &self,
21094        buffer_handle: Entity<Buffer>,
21095        range: Range<text::Anchor>,
21096        cx: &mut App,
21097    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21098        Some(self.update(cx, |project, cx| {
21099            project.inlay_hints(buffer_handle, range, cx)
21100        }))
21101    }
21102
21103    fn resolve_inlay_hint(
21104        &self,
21105        hint: InlayHint,
21106        buffer_handle: Entity<Buffer>,
21107        server_id: LanguageServerId,
21108        cx: &mut App,
21109    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21110        Some(self.update(cx, |project, cx| {
21111            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21112        }))
21113    }
21114
21115    fn range_for_rename(
21116        &self,
21117        buffer: &Entity<Buffer>,
21118        position: text::Anchor,
21119        cx: &mut App,
21120    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21121        Some(self.update(cx, |project, cx| {
21122            let buffer = buffer.clone();
21123            let task = project.prepare_rename(buffer.clone(), position, cx);
21124            cx.spawn(async move |_, cx| {
21125                Ok(match task.await? {
21126                    PrepareRenameResponse::Success(range) => Some(range),
21127                    PrepareRenameResponse::InvalidPosition => None,
21128                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21129                        // Fallback on using TreeSitter info to determine identifier range
21130                        buffer.read_with(cx, |buffer, _| {
21131                            let snapshot = buffer.snapshot();
21132                            let (range, kind) = snapshot.surrounding_word(position);
21133                            if kind != Some(CharKind::Word) {
21134                                return None;
21135                            }
21136                            Some(
21137                                snapshot.anchor_before(range.start)
21138                                    ..snapshot.anchor_after(range.end),
21139                            )
21140                        })?
21141                    }
21142                })
21143            })
21144        }))
21145    }
21146
21147    fn perform_rename(
21148        &self,
21149        buffer: &Entity<Buffer>,
21150        position: text::Anchor,
21151        new_name: String,
21152        cx: &mut App,
21153    ) -> Option<Task<Result<ProjectTransaction>>> {
21154        Some(self.update(cx, |project, cx| {
21155            project.perform_rename(buffer.clone(), position, new_name, cx)
21156        }))
21157    }
21158
21159    fn pull_diagnostics_for_buffer(
21160        &self,
21161        buffer: Entity<Buffer>,
21162        cx: &mut App,
21163    ) -> Task<anyhow::Result<()>> {
21164        let diagnostics = self.update(cx, |project, cx| {
21165            project
21166                .lsp_store()
21167                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21168        });
21169        let project = self.clone();
21170        cx.spawn(async move |cx| {
21171            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21172            project.update(cx, |project, cx| {
21173                project.lsp_store().update(cx, |lsp_store, cx| {
21174                    for diagnostics_set in diagnostics {
21175                        let LspPullDiagnostics::Response {
21176                            server_id,
21177                            uri,
21178                            diagnostics,
21179                        } = diagnostics_set
21180                        else {
21181                            continue;
21182                        };
21183
21184                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21185                        let disk_based_sources = adapter
21186                            .as_ref()
21187                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21188                            .unwrap_or(&[]);
21189                        match diagnostics {
21190                            PulledDiagnostics::Unchanged { result_id } => {
21191                                lsp_store
21192                                    .merge_diagnostics(
21193                                        server_id,
21194                                        lsp::PublishDiagnosticsParams {
21195                                            uri: uri.clone(),
21196                                            diagnostics: Vec::new(),
21197                                            version: None,
21198                                        },
21199                                        Some(result_id),
21200                                        DiagnosticSourceKind::Pulled,
21201                                        disk_based_sources,
21202                                        |_, _| true,
21203                                        cx,
21204                                    )
21205                                    .log_err();
21206                            }
21207                            PulledDiagnostics::Changed {
21208                                diagnostics,
21209                                result_id,
21210                            } => {
21211                                lsp_store
21212                                    .merge_diagnostics(
21213                                        server_id,
21214                                        lsp::PublishDiagnosticsParams {
21215                                            uri: uri.clone(),
21216                                            diagnostics,
21217                                            version: None,
21218                                        },
21219                                        result_id,
21220                                        DiagnosticSourceKind::Pulled,
21221                                        disk_based_sources,
21222                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21223                                            DiagnosticSourceKind::Pulled => false,
21224                                            DiagnosticSourceKind::Other
21225                                            | DiagnosticSourceKind::Pushed => true,
21226                                        },
21227                                        cx,
21228                                    )
21229                                    .log_err();
21230                            }
21231                        }
21232                    }
21233                })
21234            })
21235        })
21236    }
21237}
21238
21239fn inlay_hint_settings(
21240    location: Anchor,
21241    snapshot: &MultiBufferSnapshot,
21242    cx: &mut Context<Editor>,
21243) -> InlayHintSettings {
21244    let file = snapshot.file_at(location);
21245    let language = snapshot.language_at(location).map(|l| l.name());
21246    language_settings(language, file, cx).inlay_hints
21247}
21248
21249fn consume_contiguous_rows(
21250    contiguous_row_selections: &mut Vec<Selection<Point>>,
21251    selection: &Selection<Point>,
21252    display_map: &DisplaySnapshot,
21253    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21254) -> (MultiBufferRow, MultiBufferRow) {
21255    contiguous_row_selections.push(selection.clone());
21256    let start_row = MultiBufferRow(selection.start.row);
21257    let mut end_row = ending_row(selection, display_map);
21258
21259    while let Some(next_selection) = selections.peek() {
21260        if next_selection.start.row <= end_row.0 {
21261            end_row = ending_row(next_selection, display_map);
21262            contiguous_row_selections.push(selections.next().unwrap().clone());
21263        } else {
21264            break;
21265        }
21266    }
21267    (start_row, end_row)
21268}
21269
21270fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21271    if next_selection.end.column > 0 || next_selection.is_empty() {
21272        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21273    } else {
21274        MultiBufferRow(next_selection.end.row)
21275    }
21276}
21277
21278impl EditorSnapshot {
21279    pub fn remote_selections_in_range<'a>(
21280        &'a self,
21281        range: &'a Range<Anchor>,
21282        collaboration_hub: &dyn CollaborationHub,
21283        cx: &'a App,
21284    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21285        let participant_names = collaboration_hub.user_names(cx);
21286        let participant_indices = collaboration_hub.user_participant_indices(cx);
21287        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21288        let collaborators_by_replica_id = collaborators_by_peer_id
21289            .values()
21290            .map(|collaborator| (collaborator.replica_id, collaborator))
21291            .collect::<HashMap<_, _>>();
21292        self.buffer_snapshot
21293            .selections_in_range(range, false)
21294            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21295                if replica_id == AGENT_REPLICA_ID {
21296                    Some(RemoteSelection {
21297                        replica_id,
21298                        selection,
21299                        cursor_shape,
21300                        line_mode,
21301                        collaborator_id: CollaboratorId::Agent,
21302                        user_name: Some("Agent".into()),
21303                        color: cx.theme().players().agent(),
21304                    })
21305                } else {
21306                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21307                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21308                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21309                    Some(RemoteSelection {
21310                        replica_id,
21311                        selection,
21312                        cursor_shape,
21313                        line_mode,
21314                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21315                        user_name,
21316                        color: if let Some(index) = participant_index {
21317                            cx.theme().players().color_for_participant(index.0)
21318                        } else {
21319                            cx.theme().players().absent()
21320                        },
21321                    })
21322                }
21323            })
21324    }
21325
21326    pub fn hunks_for_ranges(
21327        &self,
21328        ranges: impl IntoIterator<Item = Range<Point>>,
21329    ) -> Vec<MultiBufferDiffHunk> {
21330        let mut hunks = Vec::new();
21331        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21332            HashMap::default();
21333        for query_range in ranges {
21334            let query_rows =
21335                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21336            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21337                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21338            ) {
21339                // Include deleted hunks that are adjacent to the query range, because
21340                // otherwise they would be missed.
21341                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21342                if hunk.status().is_deleted() {
21343                    intersects_range |= hunk.row_range.start == query_rows.end;
21344                    intersects_range |= hunk.row_range.end == query_rows.start;
21345                }
21346                if intersects_range {
21347                    if !processed_buffer_rows
21348                        .entry(hunk.buffer_id)
21349                        .or_default()
21350                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21351                    {
21352                        continue;
21353                    }
21354                    hunks.push(hunk);
21355                }
21356            }
21357        }
21358
21359        hunks
21360    }
21361
21362    fn display_diff_hunks_for_rows<'a>(
21363        &'a self,
21364        display_rows: Range<DisplayRow>,
21365        folded_buffers: &'a HashSet<BufferId>,
21366    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21367        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21368        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21369
21370        self.buffer_snapshot
21371            .diff_hunks_in_range(buffer_start..buffer_end)
21372            .filter_map(|hunk| {
21373                if folded_buffers.contains(&hunk.buffer_id) {
21374                    return None;
21375                }
21376
21377                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21378                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21379
21380                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21381                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21382
21383                let display_hunk = if hunk_display_start.column() != 0 {
21384                    DisplayDiffHunk::Folded {
21385                        display_row: hunk_display_start.row(),
21386                    }
21387                } else {
21388                    let mut end_row = hunk_display_end.row();
21389                    if hunk_display_end.column() > 0 {
21390                        end_row.0 += 1;
21391                    }
21392                    let is_created_file = hunk.is_created_file();
21393                    DisplayDiffHunk::Unfolded {
21394                        status: hunk.status(),
21395                        diff_base_byte_range: hunk.diff_base_byte_range,
21396                        display_row_range: hunk_display_start.row()..end_row,
21397                        multi_buffer_range: Anchor::range_in_buffer(
21398                            hunk.excerpt_id,
21399                            hunk.buffer_id,
21400                            hunk.buffer_range,
21401                        ),
21402                        is_created_file,
21403                    }
21404                };
21405
21406                Some(display_hunk)
21407            })
21408    }
21409
21410    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21411        self.display_snapshot.buffer_snapshot.language_at(position)
21412    }
21413
21414    pub fn is_focused(&self) -> bool {
21415        self.is_focused
21416    }
21417
21418    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21419        self.placeholder_text.as_ref()
21420    }
21421
21422    pub fn scroll_position(&self) -> gpui::Point<f32> {
21423        self.scroll_anchor.scroll_position(&self.display_snapshot)
21424    }
21425
21426    fn gutter_dimensions(
21427        &self,
21428        font_id: FontId,
21429        font_size: Pixels,
21430        max_line_number_width: Pixels,
21431        cx: &App,
21432    ) -> Option<GutterDimensions> {
21433        if !self.show_gutter {
21434            return None;
21435        }
21436
21437        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21438        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21439
21440        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21441            matches!(
21442                ProjectSettings::get_global(cx).git.git_gutter,
21443                Some(GitGutterSetting::TrackedFiles)
21444            )
21445        });
21446        let gutter_settings = EditorSettings::get_global(cx).gutter;
21447        let show_line_numbers = self
21448            .show_line_numbers
21449            .unwrap_or(gutter_settings.line_numbers);
21450        let line_gutter_width = if show_line_numbers {
21451            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21452            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21453            max_line_number_width.max(min_width_for_number_on_gutter)
21454        } else {
21455            0.0.into()
21456        };
21457
21458        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21459        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21460
21461        let git_blame_entries_width =
21462            self.git_blame_gutter_max_author_length
21463                .map(|max_author_length| {
21464                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21465                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21466
21467                    /// The number of characters to dedicate to gaps and margins.
21468                    const SPACING_WIDTH: usize = 4;
21469
21470                    let max_char_count = max_author_length.min(renderer.max_author_length())
21471                        + ::git::SHORT_SHA_LENGTH
21472                        + MAX_RELATIVE_TIMESTAMP.len()
21473                        + SPACING_WIDTH;
21474
21475                    em_advance * max_char_count
21476                });
21477
21478        let is_singleton = self.buffer_snapshot.is_singleton();
21479
21480        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21481        left_padding += if !is_singleton {
21482            em_width * 4.0
21483        } else if show_runnables || show_breakpoints {
21484            em_width * 3.0
21485        } else if show_git_gutter && show_line_numbers {
21486            em_width * 2.0
21487        } else if show_git_gutter || show_line_numbers {
21488            em_width
21489        } else {
21490            px(0.)
21491        };
21492
21493        let shows_folds = is_singleton && gutter_settings.folds;
21494
21495        let right_padding = if shows_folds && show_line_numbers {
21496            em_width * 4.0
21497        } else if shows_folds || (!is_singleton && show_line_numbers) {
21498            em_width * 3.0
21499        } else if show_line_numbers {
21500            em_width
21501        } else {
21502            px(0.)
21503        };
21504
21505        Some(GutterDimensions {
21506            left_padding,
21507            right_padding,
21508            width: line_gutter_width + left_padding + right_padding,
21509            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21510            git_blame_entries_width,
21511        })
21512    }
21513
21514    pub fn render_crease_toggle(
21515        &self,
21516        buffer_row: MultiBufferRow,
21517        row_contains_cursor: bool,
21518        editor: Entity<Editor>,
21519        window: &mut Window,
21520        cx: &mut App,
21521    ) -> Option<AnyElement> {
21522        let folded = self.is_line_folded(buffer_row);
21523        let mut is_foldable = false;
21524
21525        if let Some(crease) = self
21526            .crease_snapshot
21527            .query_row(buffer_row, &self.buffer_snapshot)
21528        {
21529            is_foldable = true;
21530            match crease {
21531                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21532                    if let Some(render_toggle) = render_toggle {
21533                        let toggle_callback =
21534                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21535                                if folded {
21536                                    editor.update(cx, |editor, cx| {
21537                                        editor.fold_at(buffer_row, window, cx)
21538                                    });
21539                                } else {
21540                                    editor.update(cx, |editor, cx| {
21541                                        editor.unfold_at(buffer_row, window, cx)
21542                                    });
21543                                }
21544                            });
21545                        return Some((render_toggle)(
21546                            buffer_row,
21547                            folded,
21548                            toggle_callback,
21549                            window,
21550                            cx,
21551                        ));
21552                    }
21553                }
21554            }
21555        }
21556
21557        is_foldable |= self.starts_indent(buffer_row);
21558
21559        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21560            Some(
21561                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21562                    .toggle_state(folded)
21563                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21564                        if folded {
21565                            this.unfold_at(buffer_row, window, cx);
21566                        } else {
21567                            this.fold_at(buffer_row, window, cx);
21568                        }
21569                    }))
21570                    .into_any_element(),
21571            )
21572        } else {
21573            None
21574        }
21575    }
21576
21577    pub fn render_crease_trailer(
21578        &self,
21579        buffer_row: MultiBufferRow,
21580        window: &mut Window,
21581        cx: &mut App,
21582    ) -> Option<AnyElement> {
21583        let folded = self.is_line_folded(buffer_row);
21584        if let Crease::Inline { render_trailer, .. } = self
21585            .crease_snapshot
21586            .query_row(buffer_row, &self.buffer_snapshot)?
21587        {
21588            let render_trailer = render_trailer.as_ref()?;
21589            Some(render_trailer(buffer_row, folded, window, cx))
21590        } else {
21591            None
21592        }
21593    }
21594}
21595
21596impl Deref for EditorSnapshot {
21597    type Target = DisplaySnapshot;
21598
21599    fn deref(&self) -> &Self::Target {
21600        &self.display_snapshot
21601    }
21602}
21603
21604#[derive(Clone, Debug, PartialEq, Eq)]
21605pub enum EditorEvent {
21606    InputIgnored {
21607        text: Arc<str>,
21608    },
21609    InputHandled {
21610        utf16_range_to_replace: Option<Range<isize>>,
21611        text: Arc<str>,
21612    },
21613    ExcerptsAdded {
21614        buffer: Entity<Buffer>,
21615        predecessor: ExcerptId,
21616        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21617    },
21618    ExcerptsRemoved {
21619        ids: Vec<ExcerptId>,
21620        removed_buffer_ids: Vec<BufferId>,
21621    },
21622    BufferFoldToggled {
21623        ids: Vec<ExcerptId>,
21624        folded: bool,
21625    },
21626    ExcerptsEdited {
21627        ids: Vec<ExcerptId>,
21628    },
21629    ExcerptsExpanded {
21630        ids: Vec<ExcerptId>,
21631    },
21632    BufferEdited,
21633    Edited {
21634        transaction_id: clock::Lamport,
21635    },
21636    Reparsed(BufferId),
21637    Focused,
21638    FocusedIn,
21639    Blurred,
21640    DirtyChanged,
21641    Saved,
21642    TitleChanged,
21643    DiffBaseChanged,
21644    SelectionsChanged {
21645        local: bool,
21646    },
21647    ScrollPositionChanged {
21648        local: bool,
21649        autoscroll: bool,
21650    },
21651    Closed,
21652    TransactionUndone {
21653        transaction_id: clock::Lamport,
21654    },
21655    TransactionBegun {
21656        transaction_id: clock::Lamport,
21657    },
21658    Reloaded,
21659    CursorShapeChanged,
21660    PushedToNavHistory {
21661        anchor: Anchor,
21662        is_deactivate: bool,
21663    },
21664}
21665
21666impl EventEmitter<EditorEvent> for Editor {}
21667
21668impl Focusable for Editor {
21669    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21670        self.focus_handle.clone()
21671    }
21672}
21673
21674impl Render for Editor {
21675    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21676        let settings = ThemeSettings::get_global(cx);
21677
21678        let mut text_style = match self.mode {
21679            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21680                color: cx.theme().colors().editor_foreground,
21681                font_family: settings.ui_font.family.clone(),
21682                font_features: settings.ui_font.features.clone(),
21683                font_fallbacks: settings.ui_font.fallbacks.clone(),
21684                font_size: rems(0.875).into(),
21685                font_weight: settings.ui_font.weight,
21686                line_height: relative(settings.buffer_line_height.value()),
21687                ..Default::default()
21688            },
21689            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21690                color: cx.theme().colors().editor_foreground,
21691                font_family: settings.buffer_font.family.clone(),
21692                font_features: settings.buffer_font.features.clone(),
21693                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21694                font_size: settings.buffer_font_size(cx).into(),
21695                font_weight: settings.buffer_font.weight,
21696                line_height: relative(settings.buffer_line_height.value()),
21697                ..Default::default()
21698            },
21699        };
21700        if let Some(text_style_refinement) = &self.text_style_refinement {
21701            text_style.refine(text_style_refinement)
21702        }
21703
21704        let background = match self.mode {
21705            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21706            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21707            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21708            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21709        };
21710
21711        EditorElement::new(
21712            &cx.entity(),
21713            EditorStyle {
21714                background,
21715                local_player: cx.theme().players().local(),
21716                text: text_style,
21717                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21718                syntax: cx.theme().syntax().clone(),
21719                status: cx.theme().status().clone(),
21720                inlay_hints_style: make_inlay_hints_style(cx),
21721                inline_completion_styles: make_suggestion_styles(cx),
21722                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21723                show_underlines: !self.mode.is_minimap(),
21724            },
21725        )
21726    }
21727}
21728
21729impl EntityInputHandler for Editor {
21730    fn text_for_range(
21731        &mut self,
21732        range_utf16: Range<usize>,
21733        adjusted_range: &mut Option<Range<usize>>,
21734        _: &mut Window,
21735        cx: &mut Context<Self>,
21736    ) -> Option<String> {
21737        let snapshot = self.buffer.read(cx).read(cx);
21738        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21739        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21740        if (start.0..end.0) != range_utf16 {
21741            adjusted_range.replace(start.0..end.0);
21742        }
21743        Some(snapshot.text_for_range(start..end).collect())
21744    }
21745
21746    fn selected_text_range(
21747        &mut self,
21748        ignore_disabled_input: bool,
21749        _: &mut Window,
21750        cx: &mut Context<Self>,
21751    ) -> Option<UTF16Selection> {
21752        // Prevent the IME menu from appearing when holding down an alphabetic key
21753        // while input is disabled.
21754        if !ignore_disabled_input && !self.input_enabled {
21755            return None;
21756        }
21757
21758        let selection = self.selections.newest::<OffsetUtf16>(cx);
21759        let range = selection.range();
21760
21761        Some(UTF16Selection {
21762            range: range.start.0..range.end.0,
21763            reversed: selection.reversed,
21764        })
21765    }
21766
21767    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21768        let snapshot = self.buffer.read(cx).read(cx);
21769        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21770        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21771    }
21772
21773    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21774        self.clear_highlights::<InputComposition>(cx);
21775        self.ime_transaction.take();
21776    }
21777
21778    fn replace_text_in_range(
21779        &mut self,
21780        range_utf16: Option<Range<usize>>,
21781        text: &str,
21782        window: &mut Window,
21783        cx: &mut Context<Self>,
21784    ) {
21785        if !self.input_enabled {
21786            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21787            return;
21788        }
21789
21790        self.transact(window, cx, |this, window, cx| {
21791            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21792                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21793                Some(this.selection_replacement_ranges(range_utf16, cx))
21794            } else {
21795                this.marked_text_ranges(cx)
21796            };
21797
21798            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21799                let newest_selection_id = this.selections.newest_anchor().id;
21800                this.selections
21801                    .all::<OffsetUtf16>(cx)
21802                    .iter()
21803                    .zip(ranges_to_replace.iter())
21804                    .find_map(|(selection, range)| {
21805                        if selection.id == newest_selection_id {
21806                            Some(
21807                                (range.start.0 as isize - selection.head().0 as isize)
21808                                    ..(range.end.0 as isize - selection.head().0 as isize),
21809                            )
21810                        } else {
21811                            None
21812                        }
21813                    })
21814            });
21815
21816            cx.emit(EditorEvent::InputHandled {
21817                utf16_range_to_replace: range_to_replace,
21818                text: text.into(),
21819            });
21820
21821            if let Some(new_selected_ranges) = new_selected_ranges {
21822                this.change_selections(None, window, cx, |selections| {
21823                    selections.select_ranges(new_selected_ranges)
21824                });
21825                this.backspace(&Default::default(), window, cx);
21826            }
21827
21828            this.handle_input(text, window, cx);
21829        });
21830
21831        if let Some(transaction) = self.ime_transaction {
21832            self.buffer.update(cx, |buffer, cx| {
21833                buffer.group_until_transaction(transaction, cx);
21834            });
21835        }
21836
21837        self.unmark_text(window, cx);
21838    }
21839
21840    fn replace_and_mark_text_in_range(
21841        &mut self,
21842        range_utf16: Option<Range<usize>>,
21843        text: &str,
21844        new_selected_range_utf16: Option<Range<usize>>,
21845        window: &mut Window,
21846        cx: &mut Context<Self>,
21847    ) {
21848        if !self.input_enabled {
21849            return;
21850        }
21851
21852        let transaction = self.transact(window, cx, |this, window, cx| {
21853            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21854                let snapshot = this.buffer.read(cx).read(cx);
21855                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21856                    for marked_range in &mut marked_ranges {
21857                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21858                        marked_range.start.0 += relative_range_utf16.start;
21859                        marked_range.start =
21860                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21861                        marked_range.end =
21862                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21863                    }
21864                }
21865                Some(marked_ranges)
21866            } else if let Some(range_utf16) = range_utf16 {
21867                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21868                Some(this.selection_replacement_ranges(range_utf16, cx))
21869            } else {
21870                None
21871            };
21872
21873            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21874                let newest_selection_id = this.selections.newest_anchor().id;
21875                this.selections
21876                    .all::<OffsetUtf16>(cx)
21877                    .iter()
21878                    .zip(ranges_to_replace.iter())
21879                    .find_map(|(selection, range)| {
21880                        if selection.id == newest_selection_id {
21881                            Some(
21882                                (range.start.0 as isize - selection.head().0 as isize)
21883                                    ..(range.end.0 as isize - selection.head().0 as isize),
21884                            )
21885                        } else {
21886                            None
21887                        }
21888                    })
21889            });
21890
21891            cx.emit(EditorEvent::InputHandled {
21892                utf16_range_to_replace: range_to_replace,
21893                text: text.into(),
21894            });
21895
21896            if let Some(ranges) = ranges_to_replace {
21897                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21898            }
21899
21900            let marked_ranges = {
21901                let snapshot = this.buffer.read(cx).read(cx);
21902                this.selections
21903                    .disjoint_anchors()
21904                    .iter()
21905                    .map(|selection| {
21906                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21907                    })
21908                    .collect::<Vec<_>>()
21909            };
21910
21911            if text.is_empty() {
21912                this.unmark_text(window, cx);
21913            } else {
21914                this.highlight_text::<InputComposition>(
21915                    marked_ranges.clone(),
21916                    HighlightStyle {
21917                        underline: Some(UnderlineStyle {
21918                            thickness: px(1.),
21919                            color: None,
21920                            wavy: false,
21921                        }),
21922                        ..Default::default()
21923                    },
21924                    cx,
21925                );
21926            }
21927
21928            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21929            let use_autoclose = this.use_autoclose;
21930            let use_auto_surround = this.use_auto_surround;
21931            this.set_use_autoclose(false);
21932            this.set_use_auto_surround(false);
21933            this.handle_input(text, window, cx);
21934            this.set_use_autoclose(use_autoclose);
21935            this.set_use_auto_surround(use_auto_surround);
21936
21937            if let Some(new_selected_range) = new_selected_range_utf16 {
21938                let snapshot = this.buffer.read(cx).read(cx);
21939                let new_selected_ranges = marked_ranges
21940                    .into_iter()
21941                    .map(|marked_range| {
21942                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21943                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21944                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21945                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21946                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21947                    })
21948                    .collect::<Vec<_>>();
21949
21950                drop(snapshot);
21951                this.change_selections(None, window, cx, |selections| {
21952                    selections.select_ranges(new_selected_ranges)
21953                });
21954            }
21955        });
21956
21957        self.ime_transaction = self.ime_transaction.or(transaction);
21958        if let Some(transaction) = self.ime_transaction {
21959            self.buffer.update(cx, |buffer, cx| {
21960                buffer.group_until_transaction(transaction, cx);
21961            });
21962        }
21963
21964        if self.text_highlights::<InputComposition>(cx).is_none() {
21965            self.ime_transaction.take();
21966        }
21967    }
21968
21969    fn bounds_for_range(
21970        &mut self,
21971        range_utf16: Range<usize>,
21972        element_bounds: gpui::Bounds<Pixels>,
21973        window: &mut Window,
21974        cx: &mut Context<Self>,
21975    ) -> Option<gpui::Bounds<Pixels>> {
21976        let text_layout_details = self.text_layout_details(window);
21977        let gpui::Size {
21978            width: em_width,
21979            height: line_height,
21980        } = self.character_size(window);
21981
21982        let snapshot = self.snapshot(window, cx);
21983        let scroll_position = snapshot.scroll_position();
21984        let scroll_left = scroll_position.x * em_width;
21985
21986        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21987        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21988            + self.gutter_dimensions.width
21989            + self.gutter_dimensions.margin;
21990        let y = line_height * (start.row().as_f32() - scroll_position.y);
21991
21992        Some(Bounds {
21993            origin: element_bounds.origin + point(x, y),
21994            size: size(em_width, line_height),
21995        })
21996    }
21997
21998    fn character_index_for_point(
21999        &mut self,
22000        point: gpui::Point<Pixels>,
22001        _window: &mut Window,
22002        _cx: &mut Context<Self>,
22003    ) -> Option<usize> {
22004        let position_map = self.last_position_map.as_ref()?;
22005        if !position_map.text_hitbox.contains(&point) {
22006            return None;
22007        }
22008        let display_point = position_map.point_for_position(point).previous_valid;
22009        let anchor = position_map
22010            .snapshot
22011            .display_point_to_anchor(display_point, Bias::Left);
22012        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22013        Some(utf16_offset.0)
22014    }
22015}
22016
22017trait SelectionExt {
22018    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22019    fn spanned_rows(
22020        &self,
22021        include_end_if_at_line_start: bool,
22022        map: &DisplaySnapshot,
22023    ) -> Range<MultiBufferRow>;
22024}
22025
22026impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22027    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22028        let start = self
22029            .start
22030            .to_point(&map.buffer_snapshot)
22031            .to_display_point(map);
22032        let end = self
22033            .end
22034            .to_point(&map.buffer_snapshot)
22035            .to_display_point(map);
22036        if self.reversed {
22037            end..start
22038        } else {
22039            start..end
22040        }
22041    }
22042
22043    fn spanned_rows(
22044        &self,
22045        include_end_if_at_line_start: bool,
22046        map: &DisplaySnapshot,
22047    ) -> Range<MultiBufferRow> {
22048        let start = self.start.to_point(&map.buffer_snapshot);
22049        let mut end = self.end.to_point(&map.buffer_snapshot);
22050        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22051            end.row -= 1;
22052        }
22053
22054        let buffer_start = map.prev_line_boundary(start).0;
22055        let buffer_end = map.next_line_boundary(end).0;
22056        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22057    }
22058}
22059
22060impl<T: InvalidationRegion> InvalidationStack<T> {
22061    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22062    where
22063        S: Clone + ToOffset,
22064    {
22065        while let Some(region) = self.last() {
22066            let all_selections_inside_invalidation_ranges =
22067                if selections.len() == region.ranges().len() {
22068                    selections
22069                        .iter()
22070                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22071                        .all(|(selection, invalidation_range)| {
22072                            let head = selection.head().to_offset(buffer);
22073                            invalidation_range.start <= head && invalidation_range.end >= head
22074                        })
22075                } else {
22076                    false
22077                };
22078
22079            if all_selections_inside_invalidation_ranges {
22080                break;
22081            } else {
22082                self.pop();
22083            }
22084        }
22085    }
22086}
22087
22088impl<T> Default for InvalidationStack<T> {
22089    fn default() -> Self {
22090        Self(Default::default())
22091    }
22092}
22093
22094impl<T> Deref for InvalidationStack<T> {
22095    type Target = Vec<T>;
22096
22097    fn deref(&self) -> &Self::Target {
22098        &self.0
22099    }
22100}
22101
22102impl<T> DerefMut for InvalidationStack<T> {
22103    fn deref_mut(&mut self) -> &mut Self::Target {
22104        &mut self.0
22105    }
22106}
22107
22108impl InvalidationRegion for SnippetState {
22109    fn ranges(&self) -> &[Range<Anchor>] {
22110        &self.ranges[self.active_index]
22111    }
22112}
22113
22114fn inline_completion_edit_text(
22115    current_snapshot: &BufferSnapshot,
22116    edits: &[(Range<Anchor>, String)],
22117    edit_preview: &EditPreview,
22118    include_deletions: bool,
22119    cx: &App,
22120) -> HighlightedText {
22121    let edits = edits
22122        .iter()
22123        .map(|(anchor, text)| {
22124            (
22125                anchor.start.text_anchor..anchor.end.text_anchor,
22126                text.clone(),
22127            )
22128        })
22129        .collect::<Vec<_>>();
22130
22131    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22132}
22133
22134pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22135    match severity {
22136        lsp::DiagnosticSeverity::ERROR => colors.error,
22137        lsp::DiagnosticSeverity::WARNING => colors.warning,
22138        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22139        lsp::DiagnosticSeverity::HINT => colors.info,
22140        _ => colors.ignored,
22141    }
22142}
22143
22144pub fn styled_runs_for_code_label<'a>(
22145    label: &'a CodeLabel,
22146    syntax_theme: &'a theme::SyntaxTheme,
22147) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22148    let fade_out = HighlightStyle {
22149        fade_out: Some(0.35),
22150        ..Default::default()
22151    };
22152
22153    let mut prev_end = label.filter_range.end;
22154    label
22155        .runs
22156        .iter()
22157        .enumerate()
22158        .flat_map(move |(ix, (range, highlight_id))| {
22159            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22160                style
22161            } else {
22162                return Default::default();
22163            };
22164            let mut muted_style = style;
22165            muted_style.highlight(fade_out);
22166
22167            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22168            if range.start >= label.filter_range.end {
22169                if range.start > prev_end {
22170                    runs.push((prev_end..range.start, fade_out));
22171                }
22172                runs.push((range.clone(), muted_style));
22173            } else if range.end <= label.filter_range.end {
22174                runs.push((range.clone(), style));
22175            } else {
22176                runs.push((range.start..label.filter_range.end, style));
22177                runs.push((label.filter_range.end..range.end, muted_style));
22178            }
22179            prev_end = cmp::max(prev_end, range.end);
22180
22181            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22182                runs.push((prev_end..label.text.len(), fade_out));
22183            }
22184
22185            runs
22186        })
22187}
22188
22189pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22190    let mut prev_index = 0;
22191    let mut prev_codepoint: Option<char> = None;
22192    text.char_indices()
22193        .chain([(text.len(), '\0')])
22194        .filter_map(move |(index, codepoint)| {
22195            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22196            let is_boundary = index == text.len()
22197                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22198                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22199            if is_boundary {
22200                let chunk = &text[prev_index..index];
22201                prev_index = index;
22202                Some(chunk)
22203            } else {
22204                None
22205            }
22206        })
22207}
22208
22209pub trait RangeToAnchorExt: Sized {
22210    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22211
22212    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22213        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22214        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22215    }
22216}
22217
22218impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22219    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22220        let start_offset = self.start.to_offset(snapshot);
22221        let end_offset = self.end.to_offset(snapshot);
22222        if start_offset == end_offset {
22223            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22224        } else {
22225            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22226        }
22227    }
22228}
22229
22230pub trait RowExt {
22231    fn as_f32(&self) -> f32;
22232
22233    fn next_row(&self) -> Self;
22234
22235    fn previous_row(&self) -> Self;
22236
22237    fn minus(&self, other: Self) -> u32;
22238}
22239
22240impl RowExt for DisplayRow {
22241    fn as_f32(&self) -> f32 {
22242        self.0 as f32
22243    }
22244
22245    fn next_row(&self) -> Self {
22246        Self(self.0 + 1)
22247    }
22248
22249    fn previous_row(&self) -> Self {
22250        Self(self.0.saturating_sub(1))
22251    }
22252
22253    fn minus(&self, other: Self) -> u32 {
22254        self.0 - other.0
22255    }
22256}
22257
22258impl RowExt for MultiBufferRow {
22259    fn as_f32(&self) -> f32 {
22260        self.0 as f32
22261    }
22262
22263    fn next_row(&self) -> Self {
22264        Self(self.0 + 1)
22265    }
22266
22267    fn previous_row(&self) -> Self {
22268        Self(self.0.saturating_sub(1))
22269    }
22270
22271    fn minus(&self, other: Self) -> u32 {
22272        self.0 - other.0
22273    }
22274}
22275
22276trait RowRangeExt {
22277    type Row;
22278
22279    fn len(&self) -> usize;
22280
22281    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22282}
22283
22284impl RowRangeExt for Range<MultiBufferRow> {
22285    type Row = MultiBufferRow;
22286
22287    fn len(&self) -> usize {
22288        (self.end.0 - self.start.0) as usize
22289    }
22290
22291    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22292        (self.start.0..self.end.0).map(MultiBufferRow)
22293    }
22294}
22295
22296impl RowRangeExt for Range<DisplayRow> {
22297    type Row = DisplayRow;
22298
22299    fn len(&self) -> usize {
22300        (self.end.0 - self.start.0) as usize
22301    }
22302
22303    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22304        (self.start.0..self.end.0).map(DisplayRow)
22305    }
22306}
22307
22308/// If select range has more than one line, we
22309/// just point the cursor to range.start.
22310fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22311    if range.start.row == range.end.row {
22312        range
22313    } else {
22314        range.start..range.start
22315    }
22316}
22317pub struct KillRing(ClipboardItem);
22318impl Global for KillRing {}
22319
22320const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22321
22322enum BreakpointPromptEditAction {
22323    Log,
22324    Condition,
22325    HitCondition,
22326}
22327
22328struct BreakpointPromptEditor {
22329    pub(crate) prompt: Entity<Editor>,
22330    editor: WeakEntity<Editor>,
22331    breakpoint_anchor: Anchor,
22332    breakpoint: Breakpoint,
22333    edit_action: BreakpointPromptEditAction,
22334    block_ids: HashSet<CustomBlockId>,
22335    editor_margins: Arc<Mutex<EditorMargins>>,
22336    _subscriptions: Vec<Subscription>,
22337}
22338
22339impl BreakpointPromptEditor {
22340    const MAX_LINES: u8 = 4;
22341
22342    fn new(
22343        editor: WeakEntity<Editor>,
22344        breakpoint_anchor: Anchor,
22345        breakpoint: Breakpoint,
22346        edit_action: BreakpointPromptEditAction,
22347        window: &mut Window,
22348        cx: &mut Context<Self>,
22349    ) -> Self {
22350        let base_text = match edit_action {
22351            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22352            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22353            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22354        }
22355        .map(|msg| msg.to_string())
22356        .unwrap_or_default();
22357
22358        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22359        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22360
22361        let prompt = cx.new(|cx| {
22362            let mut prompt = Editor::new(
22363                EditorMode::AutoHeight {
22364                    max_lines: Self::MAX_LINES as usize,
22365                },
22366                buffer,
22367                None,
22368                window,
22369                cx,
22370            );
22371            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22372            prompt.set_show_cursor_when_unfocused(false, cx);
22373            prompt.set_placeholder_text(
22374                match edit_action {
22375                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22376                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22377                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22378                },
22379                cx,
22380            );
22381
22382            prompt
22383        });
22384
22385        Self {
22386            prompt,
22387            editor,
22388            breakpoint_anchor,
22389            breakpoint,
22390            edit_action,
22391            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22392            block_ids: Default::default(),
22393            _subscriptions: vec![],
22394        }
22395    }
22396
22397    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22398        self.block_ids.extend(block_ids)
22399    }
22400
22401    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22402        if let Some(editor) = self.editor.upgrade() {
22403            let message = self
22404                .prompt
22405                .read(cx)
22406                .buffer
22407                .read(cx)
22408                .as_singleton()
22409                .expect("A multi buffer in breakpoint prompt isn't possible")
22410                .read(cx)
22411                .as_rope()
22412                .to_string();
22413
22414            editor.update(cx, |editor, cx| {
22415                editor.edit_breakpoint_at_anchor(
22416                    self.breakpoint_anchor,
22417                    self.breakpoint.clone(),
22418                    match self.edit_action {
22419                        BreakpointPromptEditAction::Log => {
22420                            BreakpointEditAction::EditLogMessage(message.into())
22421                        }
22422                        BreakpointPromptEditAction::Condition => {
22423                            BreakpointEditAction::EditCondition(message.into())
22424                        }
22425                        BreakpointPromptEditAction::HitCondition => {
22426                            BreakpointEditAction::EditHitCondition(message.into())
22427                        }
22428                    },
22429                    cx,
22430                );
22431
22432                editor.remove_blocks(self.block_ids.clone(), None, cx);
22433                cx.focus_self(window);
22434            });
22435        }
22436    }
22437
22438    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22439        self.editor
22440            .update(cx, |editor, cx| {
22441                editor.remove_blocks(self.block_ids.clone(), None, cx);
22442                window.focus(&editor.focus_handle);
22443            })
22444            .log_err();
22445    }
22446
22447    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22448        let settings = ThemeSettings::get_global(cx);
22449        let text_style = TextStyle {
22450            color: if self.prompt.read(cx).read_only(cx) {
22451                cx.theme().colors().text_disabled
22452            } else {
22453                cx.theme().colors().text
22454            },
22455            font_family: settings.buffer_font.family.clone(),
22456            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22457            font_size: settings.buffer_font_size(cx).into(),
22458            font_weight: settings.buffer_font.weight,
22459            line_height: relative(settings.buffer_line_height.value()),
22460            ..Default::default()
22461        };
22462        EditorElement::new(
22463            &self.prompt,
22464            EditorStyle {
22465                background: cx.theme().colors().editor_background,
22466                local_player: cx.theme().players().local(),
22467                text: text_style,
22468                ..Default::default()
22469            },
22470        )
22471    }
22472}
22473
22474impl Render for BreakpointPromptEditor {
22475    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22476        let editor_margins = *self.editor_margins.lock();
22477        let gutter_dimensions = editor_margins.gutter;
22478        h_flex()
22479            .key_context("Editor")
22480            .bg(cx.theme().colors().editor_background)
22481            .border_y_1()
22482            .border_color(cx.theme().status().info_border)
22483            .size_full()
22484            .py(window.line_height() / 2.5)
22485            .on_action(cx.listener(Self::confirm))
22486            .on_action(cx.listener(Self::cancel))
22487            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22488            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22489    }
22490}
22491
22492impl Focusable for BreakpointPromptEditor {
22493    fn focus_handle(&self, cx: &App) -> FocusHandle {
22494        self.prompt.focus_handle(cx)
22495    }
22496}
22497
22498fn all_edits_insertions_or_deletions(
22499    edits: &Vec<(Range<Anchor>, String)>,
22500    snapshot: &MultiBufferSnapshot,
22501) -> bool {
22502    let mut all_insertions = true;
22503    let mut all_deletions = true;
22504
22505    for (range, new_text) in edits.iter() {
22506        let range_is_empty = range.to_offset(&snapshot).is_empty();
22507        let text_is_empty = new_text.is_empty();
22508
22509        if range_is_empty != text_is_empty {
22510            if range_is_empty {
22511                all_deletions = false;
22512            } else {
22513                all_insertions = false;
22514            }
22515        } else {
22516            return false;
22517        }
22518
22519        if !all_insertions && !all_deletions {
22520            return false;
22521        }
22522    }
22523    all_insertions || all_deletions
22524}
22525
22526struct MissingEditPredictionKeybindingTooltip;
22527
22528impl Render for MissingEditPredictionKeybindingTooltip {
22529    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22530        ui::tooltip_container(window, cx, |container, _, cx| {
22531            container
22532                .flex_shrink_0()
22533                .max_w_80()
22534                .min_h(rems_from_px(124.))
22535                .justify_between()
22536                .child(
22537                    v_flex()
22538                        .flex_1()
22539                        .text_ui_sm(cx)
22540                        .child(Label::new("Conflict with Accept Keybinding"))
22541                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22542                )
22543                .child(
22544                    h_flex()
22545                        .pb_1()
22546                        .gap_1()
22547                        .items_end()
22548                        .w_full()
22549                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22550                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22551                        }))
22552                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22553                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22554                        })),
22555                )
22556        })
22557    }
22558}
22559
22560#[derive(Debug, Clone, Copy, PartialEq)]
22561pub struct LineHighlight {
22562    pub background: Background,
22563    pub border: Option<gpui::Hsla>,
22564    pub include_gutter: bool,
22565    pub type_id: Option<TypeId>,
22566}
22567
22568fn render_diff_hunk_controls(
22569    row: u32,
22570    status: &DiffHunkStatus,
22571    hunk_range: Range<Anchor>,
22572    is_created_file: bool,
22573    line_height: Pixels,
22574    editor: &Entity<Editor>,
22575    _window: &mut Window,
22576    cx: &mut App,
22577) -> AnyElement {
22578    h_flex()
22579        .h(line_height)
22580        .mr_1()
22581        .gap_1()
22582        .px_0p5()
22583        .pb_1()
22584        .border_x_1()
22585        .border_b_1()
22586        .border_color(cx.theme().colors().border_variant)
22587        .rounded_b_lg()
22588        .bg(cx.theme().colors().editor_background)
22589        .gap_1()
22590        .block_mouse_except_scroll()
22591        .shadow_md()
22592        .child(if status.has_secondary_hunk() {
22593            Button::new(("stage", row as u64), "Stage")
22594                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22595                .tooltip({
22596                    let focus_handle = editor.focus_handle(cx);
22597                    move |window, cx| {
22598                        Tooltip::for_action_in(
22599                            "Stage Hunk",
22600                            &::git::ToggleStaged,
22601                            &focus_handle,
22602                            window,
22603                            cx,
22604                        )
22605                    }
22606                })
22607                .on_click({
22608                    let editor = editor.clone();
22609                    move |_event, _window, cx| {
22610                        editor.update(cx, |editor, cx| {
22611                            editor.stage_or_unstage_diff_hunks(
22612                                true,
22613                                vec![hunk_range.start..hunk_range.start],
22614                                cx,
22615                            );
22616                        });
22617                    }
22618                })
22619        } else {
22620            Button::new(("unstage", row as u64), "Unstage")
22621                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22622                .tooltip({
22623                    let focus_handle = editor.focus_handle(cx);
22624                    move |window, cx| {
22625                        Tooltip::for_action_in(
22626                            "Unstage Hunk",
22627                            &::git::ToggleStaged,
22628                            &focus_handle,
22629                            window,
22630                            cx,
22631                        )
22632                    }
22633                })
22634                .on_click({
22635                    let editor = editor.clone();
22636                    move |_event, _window, cx| {
22637                        editor.update(cx, |editor, cx| {
22638                            editor.stage_or_unstage_diff_hunks(
22639                                false,
22640                                vec![hunk_range.start..hunk_range.start],
22641                                cx,
22642                            );
22643                        });
22644                    }
22645                })
22646        })
22647        .child(
22648            Button::new(("restore", row as u64), "Restore")
22649                .tooltip({
22650                    let focus_handle = editor.focus_handle(cx);
22651                    move |window, cx| {
22652                        Tooltip::for_action_in(
22653                            "Restore Hunk",
22654                            &::git::Restore,
22655                            &focus_handle,
22656                            window,
22657                            cx,
22658                        )
22659                    }
22660                })
22661                .on_click({
22662                    let editor = editor.clone();
22663                    move |_event, window, cx| {
22664                        editor.update(cx, |editor, cx| {
22665                            let snapshot = editor.snapshot(window, cx);
22666                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22667                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22668                        });
22669                    }
22670                })
22671                .disabled(is_created_file),
22672        )
22673        .when(
22674            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22675            |el| {
22676                el.child(
22677                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22678                        .shape(IconButtonShape::Square)
22679                        .icon_size(IconSize::Small)
22680                        // .disabled(!has_multiple_hunks)
22681                        .tooltip({
22682                            let focus_handle = editor.focus_handle(cx);
22683                            move |window, cx| {
22684                                Tooltip::for_action_in(
22685                                    "Next Hunk",
22686                                    &GoToHunk,
22687                                    &focus_handle,
22688                                    window,
22689                                    cx,
22690                                )
22691                            }
22692                        })
22693                        .on_click({
22694                            let editor = editor.clone();
22695                            move |_event, window, cx| {
22696                                editor.update(cx, |editor, cx| {
22697                                    let snapshot = editor.snapshot(window, cx);
22698                                    let position =
22699                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22700                                    editor.go_to_hunk_before_or_after_position(
22701                                        &snapshot,
22702                                        position,
22703                                        Direction::Next,
22704                                        window,
22705                                        cx,
22706                                    );
22707                                    editor.expand_selected_diff_hunks(cx);
22708                                });
22709                            }
22710                        }),
22711                )
22712                .child(
22713                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22714                        .shape(IconButtonShape::Square)
22715                        .icon_size(IconSize::Small)
22716                        // .disabled(!has_multiple_hunks)
22717                        .tooltip({
22718                            let focus_handle = editor.focus_handle(cx);
22719                            move |window, cx| {
22720                                Tooltip::for_action_in(
22721                                    "Previous Hunk",
22722                                    &GoToPreviousHunk,
22723                                    &focus_handle,
22724                                    window,
22725                                    cx,
22726                                )
22727                            }
22728                        })
22729                        .on_click({
22730                            let editor = editor.clone();
22731                            move |_event, window, cx| {
22732                                editor.update(cx, |editor, cx| {
22733                                    let snapshot = editor.snapshot(window, cx);
22734                                    let point =
22735                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22736                                    editor.go_to_hunk_before_or_after_position(
22737                                        &snapshot,
22738                                        point,
22739                                        Direction::Prev,
22740                                        window,
22741                                        cx,
22742                                    );
22743                                    editor.expand_selected_diff_hunks(cx);
22744                                });
22745                            }
22746                        }),
22747                )
22748            },
22749        )
22750        .into_any_element()
22751}