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, Vec<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, PartialEq, Eq)]
  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
  935/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  936///
  937/// See the [module level documentation](self) for more information.
  938pub struct Editor {
  939    focus_handle: FocusHandle,
  940    last_focused_descendant: Option<WeakFocusHandle>,
  941    /// The text buffer being edited
  942    buffer: Entity<MultiBuffer>,
  943    /// Map of how text in the buffer should be displayed.
  944    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  945    pub display_map: Entity<DisplayMap>,
  946    pub selections: SelectionsCollection,
  947    pub scroll_manager: ScrollManager,
  948    /// When inline assist editors are linked, they all render cursors because
  949    /// typing enters text into each of them, even the ones that aren't focused.
  950    pub(crate) show_cursor_when_unfocused: bool,
  951    columnar_selection_tail: Option<Anchor>,
  952    columnar_display_point: Option<DisplayPoint>,
  953    add_selections_state: Option<AddSelectionsState>,
  954    select_next_state: Option<SelectNextState>,
  955    select_prev_state: Option<SelectNextState>,
  956    selection_history: SelectionHistory,
  957    defer_selection_effects: bool,
  958    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  959    autoclose_regions: Vec<AutocloseRegion>,
  960    snippet_stack: InvalidationStack<SnippetState>,
  961    select_syntax_node_history: SelectSyntaxNodeHistory,
  962    ime_transaction: Option<TransactionId>,
  963    pub diagnostics_max_severity: DiagnosticSeverity,
  964    active_diagnostics: ActiveDiagnostic,
  965    show_inline_diagnostics: bool,
  966    inline_diagnostics_update: Task<()>,
  967    inline_diagnostics_enabled: bool,
  968    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  969    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  970    hard_wrap: Option<usize>,
  971
  972    // TODO: make this a access method
  973    pub project: Option<Entity<Project>>,
  974    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  975    completion_provider: Option<Rc<dyn CompletionProvider>>,
  976    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  977    blink_manager: Entity<BlinkManager>,
  978    show_cursor_names: bool,
  979    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  980    pub show_local_selections: bool,
  981    mode: EditorMode,
  982    show_breadcrumbs: bool,
  983    show_gutter: bool,
  984    show_scrollbars: ScrollbarAxes,
  985    minimap_visibility: MinimapVisibility,
  986    offset_content: bool,
  987    disable_expand_excerpt_buttons: bool,
  988    show_line_numbers: Option<bool>,
  989    use_relative_line_numbers: Option<bool>,
  990    show_git_diff_gutter: Option<bool>,
  991    show_code_actions: Option<bool>,
  992    show_runnables: Option<bool>,
  993    show_breakpoints: Option<bool>,
  994    show_wrap_guides: Option<bool>,
  995    show_indent_guides: Option<bool>,
  996    placeholder_text: Option<Arc<str>>,
  997    highlight_order: usize,
  998    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  999    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1000    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1001    scrollbar_marker_state: ScrollbarMarkerState,
 1002    active_indent_guides_state: ActiveIndentGuidesState,
 1003    nav_history: Option<ItemNavHistory>,
 1004    context_menu: RefCell<Option<CodeContextMenu>>,
 1005    context_menu_options: Option<ContextMenuOptions>,
 1006    mouse_context_menu: Option<MouseContextMenu>,
 1007    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1008    inline_blame_popover: Option<InlineBlamePopover>,
 1009    signature_help_state: SignatureHelpState,
 1010    auto_signature_help: Option<bool>,
 1011    find_all_references_task_sources: Vec<Anchor>,
 1012    next_completion_id: CompletionId,
 1013    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1014    code_actions_task: Option<Task<Result<()>>>,
 1015    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1016    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    document_highlights_task: Option<Task<()>>,
 1018    linked_editing_range_task: Option<Task<Option<()>>>,
 1019    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1020    pending_rename: Option<RenameState>,
 1021    searchable: bool,
 1022    cursor_shape: CursorShape,
 1023    current_line_highlight: Option<CurrentLineHighlight>,
 1024    collapse_matches: bool,
 1025    autoindent_mode: Option<AutoindentMode>,
 1026    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1027    input_enabled: bool,
 1028    use_modal_editing: bool,
 1029    read_only: bool,
 1030    leader_id: Option<CollaboratorId>,
 1031    remote_id: Option<ViewId>,
 1032    pub hover_state: HoverState,
 1033    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1034    gutter_hovered: bool,
 1035    hovered_link_state: Option<HoveredLinkState>,
 1036    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1037    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1038    active_inline_completion: Option<InlineCompletionState>,
 1039    /// Used to prevent flickering as the user types while the menu is open
 1040    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1041    edit_prediction_settings: EditPredictionSettings,
 1042    inline_completions_hidden_for_vim_mode: bool,
 1043    show_inline_completions_override: Option<bool>,
 1044    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1045    edit_prediction_preview: EditPredictionPreview,
 1046    edit_prediction_indent_conflict: bool,
 1047    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1048    inlay_hint_cache: InlayHintCache,
 1049    next_inlay_id: usize,
 1050    _subscriptions: Vec<Subscription>,
 1051    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1052    gutter_dimensions: GutterDimensions,
 1053    style: Option<EditorStyle>,
 1054    text_style_refinement: Option<TextStyleRefinement>,
 1055    next_editor_action_id: EditorActionId,
 1056    editor_actions:
 1057        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1058    use_autoclose: bool,
 1059    use_auto_surround: bool,
 1060    auto_replace_emoji_shortcode: bool,
 1061    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1062    show_git_blame_gutter: bool,
 1063    show_git_blame_inline: bool,
 1064    show_git_blame_inline_delay_task: Option<Task<()>>,
 1065    git_blame_inline_enabled: bool,
 1066    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1067    serialize_dirty_buffers: bool,
 1068    show_selection_menu: Option<bool>,
 1069    blame: Option<Entity<GitBlame>>,
 1070    blame_subscription: Option<Subscription>,
 1071    custom_context_menu: Option<
 1072        Box<
 1073            dyn 'static
 1074                + Fn(
 1075                    &mut Self,
 1076                    DisplayPoint,
 1077                    &mut Window,
 1078                    &mut Context<Self>,
 1079                ) -> Option<Entity<ui::ContextMenu>>,
 1080        >,
 1081    >,
 1082    last_bounds: Option<Bounds<Pixels>>,
 1083    last_position_map: Option<Rc<PositionMap>>,
 1084    expect_bounds_change: Option<Bounds<Pixels>>,
 1085    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1086    tasks_update_task: Option<Task<()>>,
 1087    breakpoint_store: Option<Entity<BreakpointStore>>,
 1088    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1089    pull_diagnostics_task: Task<()>,
 1090    in_project_search: bool,
 1091    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1092    breadcrumb_header: Option<String>,
 1093    focused_block: Option<FocusedBlock>,
 1094    next_scroll_position: NextScrollCursorCenterTopBottom,
 1095    addons: HashMap<TypeId, Box<dyn Addon>>,
 1096    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1097    load_diff_task: Option<Shared<Task<()>>>,
 1098    /// Whether we are temporarily displaying a diff other than git's
 1099    temporary_diff_override: bool,
 1100    selection_mark_mode: bool,
 1101    toggle_fold_multiple_buffers: Task<()>,
 1102    _scroll_cursor_center_top_bottom_task: Task<()>,
 1103    serialize_selections: Task<()>,
 1104    serialize_folds: Task<()>,
 1105    mouse_cursor_hidden: bool,
 1106    minimap: Option<Entity<Self>>,
 1107    hide_mouse_mode: HideMouseMode,
 1108    pub change_list: ChangeList,
 1109    inline_value_cache: InlineValueCache,
 1110    selection_drag_state: SelectionDragState,
 1111    drag_and_drop_selection_enabled: bool,
 1112}
 1113
 1114#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1115enum NextScrollCursorCenterTopBottom {
 1116    #[default]
 1117    Center,
 1118    Top,
 1119    Bottom,
 1120}
 1121
 1122impl NextScrollCursorCenterTopBottom {
 1123    fn next(&self) -> Self {
 1124        match self {
 1125            Self::Center => Self::Top,
 1126            Self::Top => Self::Bottom,
 1127            Self::Bottom => Self::Center,
 1128        }
 1129    }
 1130}
 1131
 1132#[derive(Clone)]
 1133pub struct EditorSnapshot {
 1134    pub mode: EditorMode,
 1135    show_gutter: bool,
 1136    show_line_numbers: Option<bool>,
 1137    show_git_diff_gutter: Option<bool>,
 1138    show_code_actions: Option<bool>,
 1139    show_runnables: Option<bool>,
 1140    show_breakpoints: Option<bool>,
 1141    git_blame_gutter_max_author_length: Option<usize>,
 1142    pub display_snapshot: DisplaySnapshot,
 1143    pub placeholder_text: Option<Arc<str>>,
 1144    is_focused: bool,
 1145    scroll_anchor: ScrollAnchor,
 1146    ongoing_scroll: OngoingScroll,
 1147    current_line_highlight: CurrentLineHighlight,
 1148    gutter_hovered: bool,
 1149}
 1150
 1151#[derive(Default, Debug, Clone, Copy)]
 1152pub struct GutterDimensions {
 1153    pub left_padding: Pixels,
 1154    pub right_padding: Pixels,
 1155    pub width: Pixels,
 1156    pub margin: Pixels,
 1157    pub git_blame_entries_width: Option<Pixels>,
 1158}
 1159
 1160impl GutterDimensions {
 1161    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1162        Self {
 1163            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1164            ..Default::default()
 1165        }
 1166    }
 1167
 1168    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1169        -cx.text_system().descent(font_id, font_size)
 1170    }
 1171    /// The full width of the space taken up by the gutter.
 1172    pub fn full_width(&self) -> Pixels {
 1173        self.margin + self.width
 1174    }
 1175
 1176    /// The width of the space reserved for the fold indicators,
 1177    /// use alongside 'justify_end' and `gutter_width` to
 1178    /// right align content with the line numbers
 1179    pub fn fold_area_width(&self) -> Pixels {
 1180        self.margin + self.right_padding
 1181    }
 1182}
 1183
 1184#[derive(Debug)]
 1185pub struct RemoteSelection {
 1186    pub replica_id: ReplicaId,
 1187    pub selection: Selection<Anchor>,
 1188    pub cursor_shape: CursorShape,
 1189    pub collaborator_id: CollaboratorId,
 1190    pub line_mode: bool,
 1191    pub user_name: Option<SharedString>,
 1192    pub color: PlayerColor,
 1193}
 1194
 1195#[derive(Clone, Debug)]
 1196struct SelectionHistoryEntry {
 1197    selections: Arc<[Selection<Anchor>]>,
 1198    select_next_state: Option<SelectNextState>,
 1199    select_prev_state: Option<SelectNextState>,
 1200    add_selections_state: Option<AddSelectionsState>,
 1201}
 1202
 1203enum SelectionHistoryMode {
 1204    Normal,
 1205    Undoing,
 1206    Redoing,
 1207}
 1208
 1209#[derive(Clone, PartialEq, Eq, Hash)]
 1210struct HoveredCursor {
 1211    replica_id: u16,
 1212    selection_id: usize,
 1213}
 1214
 1215impl Default for SelectionHistoryMode {
 1216    fn default() -> Self {
 1217        Self::Normal
 1218    }
 1219}
 1220
 1221struct DeferredSelectionEffectsState {
 1222    changed: bool,
 1223    should_update_completions: bool,
 1224    autoscroll: Option<Autoscroll>,
 1225    old_cursor_position: Anchor,
 1226    history_entry: SelectionHistoryEntry,
 1227}
 1228
 1229#[derive(Default)]
 1230struct SelectionHistory {
 1231    #[allow(clippy::type_complexity)]
 1232    selections_by_transaction:
 1233        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1234    mode: SelectionHistoryMode,
 1235    undo_stack: VecDeque<SelectionHistoryEntry>,
 1236    redo_stack: VecDeque<SelectionHistoryEntry>,
 1237}
 1238
 1239impl SelectionHistory {
 1240    fn insert_transaction(
 1241        &mut self,
 1242        transaction_id: TransactionId,
 1243        selections: Arc<[Selection<Anchor>]>,
 1244    ) {
 1245        self.selections_by_transaction
 1246            .insert(transaction_id, (selections, None));
 1247    }
 1248
 1249    #[allow(clippy::type_complexity)]
 1250    fn transaction(
 1251        &self,
 1252        transaction_id: TransactionId,
 1253    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1254        self.selections_by_transaction.get(&transaction_id)
 1255    }
 1256
 1257    #[allow(clippy::type_complexity)]
 1258    fn transaction_mut(
 1259        &mut self,
 1260        transaction_id: TransactionId,
 1261    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1262        self.selections_by_transaction.get_mut(&transaction_id)
 1263    }
 1264
 1265    fn push(&mut self, entry: SelectionHistoryEntry) {
 1266        if !entry.selections.is_empty() {
 1267            match self.mode {
 1268                SelectionHistoryMode::Normal => {
 1269                    self.push_undo(entry);
 1270                    self.redo_stack.clear();
 1271                }
 1272                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1273                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1274            }
 1275        }
 1276    }
 1277
 1278    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1279        if self
 1280            .undo_stack
 1281            .back()
 1282            .map_or(true, |e| e.selections != entry.selections)
 1283        {
 1284            self.undo_stack.push_back(entry);
 1285            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1286                self.undo_stack.pop_front();
 1287            }
 1288        }
 1289    }
 1290
 1291    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1292        if self
 1293            .redo_stack
 1294            .back()
 1295            .map_or(true, |e| e.selections != entry.selections)
 1296        {
 1297            self.redo_stack.push_back(entry);
 1298            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1299                self.redo_stack.pop_front();
 1300            }
 1301        }
 1302    }
 1303}
 1304
 1305#[derive(Clone, Copy)]
 1306pub struct RowHighlightOptions {
 1307    pub autoscroll: bool,
 1308    pub include_gutter: bool,
 1309}
 1310
 1311impl Default for RowHighlightOptions {
 1312    fn default() -> Self {
 1313        Self {
 1314            autoscroll: Default::default(),
 1315            include_gutter: true,
 1316        }
 1317    }
 1318}
 1319
 1320struct RowHighlight {
 1321    index: usize,
 1322    range: Range<Anchor>,
 1323    color: Hsla,
 1324    options: RowHighlightOptions,
 1325    type_id: TypeId,
 1326}
 1327
 1328#[derive(Clone, Debug)]
 1329struct AddSelectionsState {
 1330    groups: Vec<AddSelectionsGroup>,
 1331}
 1332
 1333#[derive(Clone, Debug)]
 1334struct AddSelectionsGroup {
 1335    above: bool,
 1336    stack: Vec<usize>,
 1337}
 1338
 1339#[derive(Clone)]
 1340struct SelectNextState {
 1341    query: AhoCorasick,
 1342    wordwise: bool,
 1343    done: bool,
 1344}
 1345
 1346impl std::fmt::Debug for SelectNextState {
 1347    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1348        f.debug_struct(std::any::type_name::<Self>())
 1349            .field("wordwise", &self.wordwise)
 1350            .field("done", &self.done)
 1351            .finish()
 1352    }
 1353}
 1354
 1355#[derive(Debug)]
 1356struct AutocloseRegion {
 1357    selection_id: usize,
 1358    range: Range<Anchor>,
 1359    pair: BracketPair,
 1360}
 1361
 1362#[derive(Debug)]
 1363struct SnippetState {
 1364    ranges: Vec<Vec<Range<Anchor>>>,
 1365    active_index: usize,
 1366    choices: Vec<Option<Vec<String>>>,
 1367}
 1368
 1369#[doc(hidden)]
 1370pub struct RenameState {
 1371    pub range: Range<Anchor>,
 1372    pub old_name: Arc<str>,
 1373    pub editor: Entity<Editor>,
 1374    block_id: CustomBlockId,
 1375}
 1376
 1377struct InvalidationStack<T>(Vec<T>);
 1378
 1379struct RegisteredInlineCompletionProvider {
 1380    provider: Arc<dyn InlineCompletionProviderHandle>,
 1381    _subscription: Subscription,
 1382}
 1383
 1384#[derive(Debug, PartialEq, Eq)]
 1385pub struct ActiveDiagnosticGroup {
 1386    pub active_range: Range<Anchor>,
 1387    pub active_message: String,
 1388    pub group_id: usize,
 1389    pub blocks: HashSet<CustomBlockId>,
 1390}
 1391
 1392#[derive(Debug, PartialEq, Eq)]
 1393
 1394pub(crate) enum ActiveDiagnostic {
 1395    None,
 1396    All,
 1397    Group(ActiveDiagnosticGroup),
 1398}
 1399
 1400#[derive(Serialize, Deserialize, Clone, Debug)]
 1401pub struct ClipboardSelection {
 1402    /// The number of bytes in this selection.
 1403    pub len: usize,
 1404    /// Whether this was a full-line selection.
 1405    pub is_entire_line: bool,
 1406    /// The indentation of the first line when this content was originally copied.
 1407    pub first_line_indent: u32,
 1408}
 1409
 1410// selections, scroll behavior, was newest selection reversed
 1411type SelectSyntaxNodeHistoryState = (
 1412    Box<[Selection<usize>]>,
 1413    SelectSyntaxNodeScrollBehavior,
 1414    bool,
 1415);
 1416
 1417#[derive(Default)]
 1418struct SelectSyntaxNodeHistory {
 1419    stack: Vec<SelectSyntaxNodeHistoryState>,
 1420    // disable temporarily to allow changing selections without losing the stack
 1421    pub disable_clearing: bool,
 1422}
 1423
 1424impl SelectSyntaxNodeHistory {
 1425    pub fn try_clear(&mut self) {
 1426        if !self.disable_clearing {
 1427            self.stack.clear();
 1428        }
 1429    }
 1430
 1431    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1432        self.stack.push(selection);
 1433    }
 1434
 1435    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1436        self.stack.pop()
 1437    }
 1438}
 1439
 1440enum SelectSyntaxNodeScrollBehavior {
 1441    CursorTop,
 1442    FitSelection,
 1443    CursorBottom,
 1444}
 1445
 1446#[derive(Debug)]
 1447pub(crate) struct NavigationData {
 1448    cursor_anchor: Anchor,
 1449    cursor_position: Point,
 1450    scroll_anchor: ScrollAnchor,
 1451    scroll_top_row: u32,
 1452}
 1453
 1454#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1455pub enum GotoDefinitionKind {
 1456    Symbol,
 1457    Declaration,
 1458    Type,
 1459    Implementation,
 1460}
 1461
 1462#[derive(Debug, Clone)]
 1463enum InlayHintRefreshReason {
 1464    ModifiersChanged(bool),
 1465    Toggle(bool),
 1466    SettingsChange(InlayHintSettings),
 1467    NewLinesShown,
 1468    BufferEdited(HashSet<Arc<Language>>),
 1469    RefreshRequested,
 1470    ExcerptsRemoved(Vec<ExcerptId>),
 1471}
 1472
 1473impl InlayHintRefreshReason {
 1474    fn description(&self) -> &'static str {
 1475        match self {
 1476            Self::ModifiersChanged(_) => "modifiers changed",
 1477            Self::Toggle(_) => "toggle",
 1478            Self::SettingsChange(_) => "settings change",
 1479            Self::NewLinesShown => "new lines shown",
 1480            Self::BufferEdited(_) => "buffer edited",
 1481            Self::RefreshRequested => "refresh requested",
 1482            Self::ExcerptsRemoved(_) => "excerpts removed",
 1483        }
 1484    }
 1485}
 1486
 1487pub enum FormatTarget {
 1488    Buffers,
 1489    Ranges(Vec<Range<MultiBufferPoint>>),
 1490}
 1491
 1492pub(crate) struct FocusedBlock {
 1493    id: BlockId,
 1494    focus_handle: WeakFocusHandle,
 1495}
 1496
 1497#[derive(Clone)]
 1498enum JumpData {
 1499    MultiBufferRow {
 1500        row: MultiBufferRow,
 1501        line_offset_from_top: u32,
 1502    },
 1503    MultiBufferPoint {
 1504        excerpt_id: ExcerptId,
 1505        position: Point,
 1506        anchor: text::Anchor,
 1507        line_offset_from_top: u32,
 1508    },
 1509}
 1510
 1511pub enum MultibufferSelectionMode {
 1512    First,
 1513    All,
 1514}
 1515
 1516#[derive(Clone, Copy, Debug, Default)]
 1517pub struct RewrapOptions {
 1518    pub override_language_settings: bool,
 1519    pub preserve_existing_whitespace: bool,
 1520}
 1521
 1522impl Editor {
 1523    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1524        let buffer = cx.new(|cx| Buffer::local("", cx));
 1525        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1526        Self::new(
 1527            EditorMode::SingleLine { auto_width: false },
 1528            buffer,
 1529            None,
 1530            window,
 1531            cx,
 1532        )
 1533    }
 1534
 1535    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1536        let buffer = cx.new(|cx| Buffer::local("", cx));
 1537        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1538        Self::new(EditorMode::full(), buffer, None, window, cx)
 1539    }
 1540
 1541    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1542        let buffer = cx.new(|cx| Buffer::local("", cx));
 1543        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1544        Self::new(
 1545            EditorMode::SingleLine { auto_width: true },
 1546            buffer,
 1547            None,
 1548            window,
 1549            cx,
 1550        )
 1551    }
 1552
 1553    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1554        let buffer = cx.new(|cx| Buffer::local("", cx));
 1555        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1556        Self::new(
 1557            EditorMode::AutoHeight { max_lines },
 1558            buffer,
 1559            None,
 1560            window,
 1561            cx,
 1562        )
 1563    }
 1564
 1565    pub fn for_buffer(
 1566        buffer: Entity<Buffer>,
 1567        project: Option<Entity<Project>>,
 1568        window: &mut Window,
 1569        cx: &mut Context<Self>,
 1570    ) -> Self {
 1571        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1572        Self::new(EditorMode::full(), buffer, project, window, cx)
 1573    }
 1574
 1575    pub fn for_multibuffer(
 1576        buffer: Entity<MultiBuffer>,
 1577        project: Option<Entity<Project>>,
 1578        window: &mut Window,
 1579        cx: &mut Context<Self>,
 1580    ) -> Self {
 1581        Self::new(EditorMode::full(), buffer, project, window, cx)
 1582    }
 1583
 1584    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1585        let mut clone = Self::new(
 1586            self.mode.clone(),
 1587            self.buffer.clone(),
 1588            self.project.clone(),
 1589            window,
 1590            cx,
 1591        );
 1592        self.display_map.update(cx, |display_map, cx| {
 1593            let snapshot = display_map.snapshot(cx);
 1594            clone.display_map.update(cx, |display_map, cx| {
 1595                display_map.set_state(&snapshot, cx);
 1596            });
 1597        });
 1598        clone.folds_did_change(cx);
 1599        clone.selections.clone_state(&self.selections);
 1600        clone.scroll_manager.clone_state(&self.scroll_manager);
 1601        clone.searchable = self.searchable;
 1602        clone.read_only = self.read_only;
 1603        clone
 1604    }
 1605
 1606    pub fn new(
 1607        mode: EditorMode,
 1608        buffer: Entity<MultiBuffer>,
 1609        project: Option<Entity<Project>>,
 1610        window: &mut Window,
 1611        cx: &mut Context<Self>,
 1612    ) -> Self {
 1613        Editor::new_internal(mode, buffer, project, None, window, cx)
 1614    }
 1615
 1616    fn new_internal(
 1617        mode: EditorMode,
 1618        buffer: Entity<MultiBuffer>,
 1619        project: Option<Entity<Project>>,
 1620        display_map: Option<Entity<DisplayMap>>,
 1621        window: &mut Window,
 1622        cx: &mut Context<Self>,
 1623    ) -> Self {
 1624        debug_assert!(
 1625            display_map.is_none() || mode.is_minimap(),
 1626            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1627        );
 1628
 1629        let full_mode = mode.is_full();
 1630        let diagnostics_max_severity = if full_mode {
 1631            EditorSettings::get_global(cx)
 1632                .diagnostics_max_severity
 1633                .unwrap_or(DiagnosticSeverity::Hint)
 1634        } else {
 1635            DiagnosticSeverity::Off
 1636        };
 1637        let style = window.text_style();
 1638        let font_size = style.font_size.to_pixels(window.rem_size());
 1639        let editor = cx.entity().downgrade();
 1640        let fold_placeholder = FoldPlaceholder {
 1641            constrain_width: true,
 1642            render: Arc::new(move |fold_id, fold_range, cx| {
 1643                let editor = editor.clone();
 1644                div()
 1645                    .id(fold_id)
 1646                    .bg(cx.theme().colors().ghost_element_background)
 1647                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1648                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1649                    .rounded_xs()
 1650                    .size_full()
 1651                    .cursor_pointer()
 1652                    .child("")
 1653                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1654                    .on_click(move |_, _window, cx| {
 1655                        editor
 1656                            .update(cx, |editor, cx| {
 1657                                editor.unfold_ranges(
 1658                                    &[fold_range.start..fold_range.end],
 1659                                    true,
 1660                                    false,
 1661                                    cx,
 1662                                );
 1663                                cx.stop_propagation();
 1664                            })
 1665                            .ok();
 1666                    })
 1667                    .into_any()
 1668            }),
 1669            merge_adjacent: true,
 1670            ..FoldPlaceholder::default()
 1671        };
 1672        let display_map = display_map.unwrap_or_else(|| {
 1673            cx.new(|cx| {
 1674                DisplayMap::new(
 1675                    buffer.clone(),
 1676                    style.font(),
 1677                    font_size,
 1678                    None,
 1679                    FILE_HEADER_HEIGHT,
 1680                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1681                    fold_placeholder,
 1682                    diagnostics_max_severity,
 1683                    cx,
 1684                )
 1685            })
 1686        });
 1687
 1688        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1689
 1690        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1691
 1692        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1693            .then(|| language_settings::SoftWrap::None);
 1694
 1695        let mut project_subscriptions = Vec::new();
 1696        if mode.is_full() {
 1697            if let Some(project) = project.as_ref() {
 1698                project_subscriptions.push(cx.subscribe_in(
 1699                    project,
 1700                    window,
 1701                    |editor, _, event, window, cx| match event {
 1702                        project::Event::RefreshCodeLens => {
 1703                            // we always query lens with actions, without storing them, always refreshing them
 1704                        }
 1705                        project::Event::RefreshInlayHints => {
 1706                            editor
 1707                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1708                        }
 1709                        project::Event::LanguageServerAdded(..)
 1710                        | project::Event::LanguageServerRemoved(..) => {
 1711                            if editor.tasks_update_task.is_none() {
 1712                                editor.tasks_update_task =
 1713                                    Some(editor.refresh_runnables(window, cx));
 1714                            }
 1715                            editor.pull_diagnostics(None, window, cx);
 1716                        }
 1717                        project::Event::SnippetEdit(id, snippet_edits) => {
 1718                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1719                                let focus_handle = editor.focus_handle(cx);
 1720                                if focus_handle.is_focused(window) {
 1721                                    let snapshot = buffer.read(cx).snapshot();
 1722                                    for (range, snippet) in snippet_edits {
 1723                                        let editor_range =
 1724                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1725                                        editor
 1726                                            .insert_snippet(
 1727                                                &[editor_range],
 1728                                                snippet.clone(),
 1729                                                window,
 1730                                                cx,
 1731                                            )
 1732                                            .ok();
 1733                                    }
 1734                                }
 1735                            }
 1736                        }
 1737                        _ => {}
 1738                    },
 1739                ));
 1740                if let Some(task_inventory) = project
 1741                    .read(cx)
 1742                    .task_store()
 1743                    .read(cx)
 1744                    .task_inventory()
 1745                    .cloned()
 1746                {
 1747                    project_subscriptions.push(cx.observe_in(
 1748                        &task_inventory,
 1749                        window,
 1750                        |editor, _, window, cx| {
 1751                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1752                        },
 1753                    ));
 1754                };
 1755
 1756                project_subscriptions.push(cx.subscribe_in(
 1757                    &project.read(cx).breakpoint_store(),
 1758                    window,
 1759                    |editor, _, event, window, cx| match event {
 1760                        BreakpointStoreEvent::ClearDebugLines => {
 1761                            editor.clear_row_highlights::<ActiveDebugLine>();
 1762                            editor.refresh_inline_values(cx);
 1763                        }
 1764                        BreakpointStoreEvent::SetDebugLine => {
 1765                            if editor.go_to_active_debug_line(window, cx) {
 1766                                cx.stop_propagation();
 1767                            }
 1768
 1769                            editor.refresh_inline_values(cx);
 1770                        }
 1771                        _ => {}
 1772                    },
 1773                ));
 1774            }
 1775        }
 1776
 1777        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1778
 1779        let inlay_hint_settings =
 1780            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1781        let focus_handle = cx.focus_handle();
 1782        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1783            .detach();
 1784        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1785            .detach();
 1786        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1787            .detach();
 1788        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1789            .detach();
 1790        cx.observe_pending_input(window, Self::observe_pending_input)
 1791            .detach();
 1792
 1793        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1794            Some(false)
 1795        } else {
 1796            None
 1797        };
 1798
 1799        let breakpoint_store = match (&mode, project.as_ref()) {
 1800            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1801            _ => None,
 1802        };
 1803
 1804        let mut code_action_providers = Vec::new();
 1805        let mut load_uncommitted_diff = None;
 1806        if let Some(project) = project.clone() {
 1807            load_uncommitted_diff = Some(
 1808                update_uncommitted_diff_for_buffer(
 1809                    cx.entity(),
 1810                    &project,
 1811                    buffer.read(cx).all_buffers(),
 1812                    buffer.clone(),
 1813                    cx,
 1814                )
 1815                .shared(),
 1816            );
 1817            code_action_providers.push(Rc::new(project) as Rc<_>);
 1818        }
 1819
 1820        let mut editor = Self {
 1821            focus_handle,
 1822            show_cursor_when_unfocused: false,
 1823            last_focused_descendant: None,
 1824            buffer: buffer.clone(),
 1825            display_map: display_map.clone(),
 1826            selections,
 1827            scroll_manager: ScrollManager::new(cx),
 1828            columnar_selection_tail: None,
 1829            columnar_display_point: None,
 1830            add_selections_state: None,
 1831            select_next_state: None,
 1832            select_prev_state: None,
 1833            selection_history: SelectionHistory::default(),
 1834            defer_selection_effects: false,
 1835            deferred_selection_effects_state: None,
 1836            autoclose_regions: Vec::new(),
 1837            snippet_stack: InvalidationStack::default(),
 1838            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1839            ime_transaction: None,
 1840            active_diagnostics: ActiveDiagnostic::None,
 1841            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1842            inline_diagnostics_update: Task::ready(()),
 1843            inline_diagnostics: Vec::new(),
 1844            soft_wrap_mode_override,
 1845            diagnostics_max_severity,
 1846            hard_wrap: None,
 1847            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1848            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1849            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1850            project,
 1851            blink_manager: blink_manager.clone(),
 1852            show_local_selections: true,
 1853            show_scrollbars: ScrollbarAxes {
 1854                horizontal: full_mode,
 1855                vertical: full_mode,
 1856            },
 1857            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1858            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1859            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1860            show_gutter: mode.is_full(),
 1861            show_line_numbers: None,
 1862            use_relative_line_numbers: None,
 1863            disable_expand_excerpt_buttons: false,
 1864            show_git_diff_gutter: None,
 1865            show_code_actions: None,
 1866            show_runnables: None,
 1867            show_breakpoints: None,
 1868            show_wrap_guides: None,
 1869            show_indent_guides,
 1870            placeholder_text: None,
 1871            highlight_order: 0,
 1872            highlighted_rows: HashMap::default(),
 1873            background_highlights: TreeMap::default(),
 1874            gutter_highlights: TreeMap::default(),
 1875            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1876            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1877            nav_history: None,
 1878            context_menu: RefCell::new(None),
 1879            context_menu_options: None,
 1880            mouse_context_menu: None,
 1881            completion_tasks: Vec::new(),
 1882            inline_blame_popover: None,
 1883            signature_help_state: SignatureHelpState::default(),
 1884            auto_signature_help: None,
 1885            find_all_references_task_sources: Vec::new(),
 1886            next_completion_id: 0,
 1887            next_inlay_id: 0,
 1888            code_action_providers,
 1889            available_code_actions: None,
 1890            code_actions_task: None,
 1891            quick_selection_highlight_task: None,
 1892            debounced_selection_highlight_task: None,
 1893            document_highlights_task: None,
 1894            linked_editing_range_task: None,
 1895            pending_rename: None,
 1896            searchable: true,
 1897            cursor_shape: EditorSettings::get_global(cx)
 1898                .cursor_shape
 1899                .unwrap_or_default(),
 1900            current_line_highlight: None,
 1901            autoindent_mode: Some(AutoindentMode::EachLine),
 1902            collapse_matches: false,
 1903            workspace: None,
 1904            input_enabled: true,
 1905            use_modal_editing: mode.is_full(),
 1906            read_only: mode.is_minimap(),
 1907            use_autoclose: true,
 1908            use_auto_surround: true,
 1909            auto_replace_emoji_shortcode: false,
 1910            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1911            leader_id: None,
 1912            remote_id: None,
 1913            hover_state: HoverState::default(),
 1914            pending_mouse_down: None,
 1915            hovered_link_state: None,
 1916            edit_prediction_provider: None,
 1917            active_inline_completion: None,
 1918            stale_inline_completion_in_menu: None,
 1919            edit_prediction_preview: EditPredictionPreview::Inactive {
 1920                released_too_fast: false,
 1921            },
 1922            inline_diagnostics_enabled: mode.is_full(),
 1923            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1924            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1925
 1926            gutter_hovered: false,
 1927            pixel_position_of_newest_cursor: None,
 1928            last_bounds: None,
 1929            last_position_map: None,
 1930            expect_bounds_change: None,
 1931            gutter_dimensions: GutterDimensions::default(),
 1932            style: None,
 1933            show_cursor_names: false,
 1934            hovered_cursors: HashMap::default(),
 1935            next_editor_action_id: EditorActionId::default(),
 1936            editor_actions: Rc::default(),
 1937            inline_completions_hidden_for_vim_mode: false,
 1938            show_inline_completions_override: None,
 1939            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1940            edit_prediction_settings: EditPredictionSettings::Disabled,
 1941            edit_prediction_indent_conflict: false,
 1942            edit_prediction_requires_modifier_in_indent_conflict: true,
 1943            custom_context_menu: None,
 1944            show_git_blame_gutter: false,
 1945            show_git_blame_inline: false,
 1946            show_selection_menu: None,
 1947            show_git_blame_inline_delay_task: None,
 1948            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1949            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1950            serialize_dirty_buffers: !mode.is_minimap()
 1951                && ProjectSettings::get_global(cx)
 1952                    .session
 1953                    .restore_unsaved_buffers,
 1954            blame: None,
 1955            blame_subscription: None,
 1956            tasks: BTreeMap::default(),
 1957
 1958            breakpoint_store,
 1959            gutter_breakpoint_indicator: (None, None),
 1960            _subscriptions: vec![
 1961                cx.observe(&buffer, Self::on_buffer_changed),
 1962                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1963                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1964                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1965                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1966                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1967                cx.observe_window_activation(window, |editor, window, cx| {
 1968                    let active = window.is_window_active();
 1969                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1970                        if active {
 1971                            blink_manager.enable(cx);
 1972                        } else {
 1973                            blink_manager.disable(cx);
 1974                        }
 1975                    });
 1976                    if active {
 1977                        editor.show_mouse_cursor();
 1978                    }
 1979                }),
 1980            ],
 1981            tasks_update_task: None,
 1982            pull_diagnostics_task: Task::ready(()),
 1983            linked_edit_ranges: Default::default(),
 1984            in_project_search: false,
 1985            previous_search_ranges: None,
 1986            breadcrumb_header: None,
 1987            focused_block: None,
 1988            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1989            addons: HashMap::default(),
 1990            registered_buffers: HashMap::default(),
 1991            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1992            selection_mark_mode: false,
 1993            toggle_fold_multiple_buffers: Task::ready(()),
 1994            serialize_selections: Task::ready(()),
 1995            serialize_folds: Task::ready(()),
 1996            text_style_refinement: None,
 1997            load_diff_task: load_uncommitted_diff,
 1998            temporary_diff_override: false,
 1999            mouse_cursor_hidden: false,
 2000            minimap: None,
 2001            hide_mouse_mode: EditorSettings::get_global(cx)
 2002                .hide_mouse
 2003                .unwrap_or_default(),
 2004            change_list: ChangeList::new(),
 2005            mode,
 2006            selection_drag_state: SelectionDragState::None,
 2007            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2008        };
 2009        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2010            editor
 2011                ._subscriptions
 2012                .push(cx.observe(breakpoints, |_, _, cx| {
 2013                    cx.notify();
 2014                }));
 2015        }
 2016        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2017        editor._subscriptions.extend(project_subscriptions);
 2018
 2019        editor._subscriptions.push(cx.subscribe_in(
 2020            &cx.entity(),
 2021            window,
 2022            |editor, _, e: &EditorEvent, window, cx| match e {
 2023                EditorEvent::ScrollPositionChanged { local, .. } => {
 2024                    if *local {
 2025                        let new_anchor = editor.scroll_manager.anchor();
 2026                        let snapshot = editor.snapshot(window, cx);
 2027                        editor.update_restoration_data(cx, move |data| {
 2028                            data.scroll_position = (
 2029                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2030                                new_anchor.offset,
 2031                            );
 2032                        });
 2033                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2034                        editor.inline_blame_popover.take();
 2035                    }
 2036                }
 2037                EditorEvent::Edited { .. } => {
 2038                    if !vim_enabled(cx) {
 2039                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2040                        let pop_state = editor
 2041                            .change_list
 2042                            .last()
 2043                            .map(|previous| {
 2044                                previous.len() == selections.len()
 2045                                    && previous.iter().enumerate().all(|(ix, p)| {
 2046                                        p.to_display_point(&map).row()
 2047                                            == selections[ix].head().row()
 2048                                    })
 2049                            })
 2050                            .unwrap_or(false);
 2051                        let new_positions = selections
 2052                            .into_iter()
 2053                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2054                            .collect();
 2055                        editor
 2056                            .change_list
 2057                            .push_to_change_list(pop_state, new_positions);
 2058                    }
 2059                }
 2060                _ => (),
 2061            },
 2062        ));
 2063
 2064        if let Some(dap_store) = editor
 2065            .project
 2066            .as_ref()
 2067            .map(|project| project.read(cx).dap_store())
 2068        {
 2069            let weak_editor = cx.weak_entity();
 2070
 2071            editor
 2072                ._subscriptions
 2073                .push(
 2074                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2075                        let session_entity = cx.entity();
 2076                        weak_editor
 2077                            .update(cx, |editor, cx| {
 2078                                editor._subscriptions.push(
 2079                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2080                                );
 2081                            })
 2082                            .ok();
 2083                    }),
 2084                );
 2085
 2086            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2087                editor
 2088                    ._subscriptions
 2089                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2090            }
 2091        }
 2092
 2093        editor.end_selection(window, cx);
 2094        editor.scroll_manager.show_scrollbars(window, cx);
 2095        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2096
 2097        if full_mode {
 2098            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2099            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2100
 2101            if editor.git_blame_inline_enabled {
 2102                editor.start_git_blame_inline(false, window, cx);
 2103            }
 2104
 2105            editor.go_to_active_debug_line(window, cx);
 2106
 2107            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2108                if let Some(project) = editor.project.as_ref() {
 2109                    let handle = project.update(cx, |project, cx| {
 2110                        project.register_buffer_with_language_servers(&buffer, cx)
 2111                    });
 2112                    editor
 2113                        .registered_buffers
 2114                        .insert(buffer.read(cx).remote_id(), handle);
 2115                }
 2116            }
 2117
 2118            editor.minimap =
 2119                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2120            editor.pull_diagnostics(None, window, cx);
 2121        }
 2122
 2123        editor.report_editor_event("Editor Opened", None, cx);
 2124        editor
 2125    }
 2126
 2127    pub fn deploy_mouse_context_menu(
 2128        &mut self,
 2129        position: gpui::Point<Pixels>,
 2130        context_menu: Entity<ContextMenu>,
 2131        window: &mut Window,
 2132        cx: &mut Context<Self>,
 2133    ) {
 2134        self.mouse_context_menu = Some(MouseContextMenu::new(
 2135            self,
 2136            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2137            context_menu,
 2138            window,
 2139            cx,
 2140        ));
 2141    }
 2142
 2143    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2144        self.mouse_context_menu
 2145            .as_ref()
 2146            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2147    }
 2148
 2149    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2150        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2151    }
 2152
 2153    fn key_context_internal(
 2154        &self,
 2155        has_active_edit_prediction: bool,
 2156        window: &Window,
 2157        cx: &App,
 2158    ) -> KeyContext {
 2159        let mut key_context = KeyContext::new_with_defaults();
 2160        key_context.add("Editor");
 2161        let mode = match self.mode {
 2162            EditorMode::SingleLine { .. } => "single_line",
 2163            EditorMode::AutoHeight { .. } => "auto_height",
 2164            EditorMode::Minimap { .. } => "minimap",
 2165            EditorMode::Full { .. } => "full",
 2166        };
 2167
 2168        if EditorSettings::jupyter_enabled(cx) {
 2169            key_context.add("jupyter");
 2170        }
 2171
 2172        key_context.set("mode", mode);
 2173        if self.pending_rename.is_some() {
 2174            key_context.add("renaming");
 2175        }
 2176
 2177        match self.context_menu.borrow().as_ref() {
 2178            Some(CodeContextMenu::Completions(_)) => {
 2179                key_context.add("menu");
 2180                key_context.add("showing_completions");
 2181            }
 2182            Some(CodeContextMenu::CodeActions(_)) => {
 2183                key_context.add("menu");
 2184                key_context.add("showing_code_actions")
 2185            }
 2186            None => {}
 2187        }
 2188
 2189        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2190        if !self.focus_handle(cx).contains_focused(window, cx)
 2191            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2192        {
 2193            for addon in self.addons.values() {
 2194                addon.extend_key_context(&mut key_context, cx)
 2195            }
 2196        }
 2197
 2198        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2199            if let Some(extension) = singleton_buffer
 2200                .read(cx)
 2201                .file()
 2202                .and_then(|file| file.path().extension()?.to_str())
 2203            {
 2204                key_context.set("extension", extension.to_string());
 2205            }
 2206        } else {
 2207            key_context.add("multibuffer");
 2208        }
 2209
 2210        if has_active_edit_prediction {
 2211            if self.edit_prediction_in_conflict() {
 2212                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2213            } else {
 2214                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2215                key_context.add("copilot_suggestion");
 2216            }
 2217        }
 2218
 2219        if self.selection_mark_mode {
 2220            key_context.add("selection_mode");
 2221        }
 2222
 2223        key_context
 2224    }
 2225
 2226    fn show_mouse_cursor(&mut self) {
 2227        self.mouse_cursor_hidden = false;
 2228    }
 2229
 2230    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2231        self.mouse_cursor_hidden = match origin {
 2232            HideMouseCursorOrigin::TypingAction => {
 2233                matches!(
 2234                    self.hide_mouse_mode,
 2235                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2236                )
 2237            }
 2238            HideMouseCursorOrigin::MovementAction => {
 2239                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2240            }
 2241        };
 2242    }
 2243
 2244    pub fn edit_prediction_in_conflict(&self) -> bool {
 2245        if !self.show_edit_predictions_in_menu() {
 2246            return false;
 2247        }
 2248
 2249        let showing_completions = self
 2250            .context_menu
 2251            .borrow()
 2252            .as_ref()
 2253            .map_or(false, |context| {
 2254                matches!(context, CodeContextMenu::Completions(_))
 2255            });
 2256
 2257        showing_completions
 2258            || self.edit_prediction_requires_modifier()
 2259            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2260            // bindings to insert tab characters.
 2261            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2262    }
 2263
 2264    pub fn accept_edit_prediction_keybind(
 2265        &self,
 2266        accept_partial: bool,
 2267        window: &Window,
 2268        cx: &App,
 2269    ) -> AcceptEditPredictionBinding {
 2270        let key_context = self.key_context_internal(true, window, cx);
 2271        let in_conflict = self.edit_prediction_in_conflict();
 2272
 2273        let bindings = if accept_partial {
 2274            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2275        } else {
 2276            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2277        };
 2278
 2279        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2280        // just the first one.
 2281        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2282            !in_conflict
 2283                || binding
 2284                    .keystrokes()
 2285                    .first()
 2286                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2287        }))
 2288    }
 2289
 2290    pub fn new_file(
 2291        workspace: &mut Workspace,
 2292        _: &workspace::NewFile,
 2293        window: &mut Window,
 2294        cx: &mut Context<Workspace>,
 2295    ) {
 2296        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2297            "Failed to create buffer",
 2298            window,
 2299            cx,
 2300            |e, _, _| match e.error_code() {
 2301                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2302                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2303                e.error_tag("required").unwrap_or("the latest version")
 2304            )),
 2305                _ => None,
 2306            },
 2307        );
 2308    }
 2309
 2310    pub fn new_in_workspace(
 2311        workspace: &mut Workspace,
 2312        window: &mut Window,
 2313        cx: &mut Context<Workspace>,
 2314    ) -> Task<Result<Entity<Editor>>> {
 2315        let project = workspace.project().clone();
 2316        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2317
 2318        cx.spawn_in(window, async move |workspace, cx| {
 2319            let buffer = create.await?;
 2320            workspace.update_in(cx, |workspace, window, cx| {
 2321                let editor =
 2322                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2323                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2324                editor
 2325            })
 2326        })
 2327    }
 2328
 2329    fn new_file_vertical(
 2330        workspace: &mut Workspace,
 2331        _: &workspace::NewFileSplitVertical,
 2332        window: &mut Window,
 2333        cx: &mut Context<Workspace>,
 2334    ) {
 2335        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2336    }
 2337
 2338    fn new_file_horizontal(
 2339        workspace: &mut Workspace,
 2340        _: &workspace::NewFileSplitHorizontal,
 2341        window: &mut Window,
 2342        cx: &mut Context<Workspace>,
 2343    ) {
 2344        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2345    }
 2346
 2347    fn new_file_in_direction(
 2348        workspace: &mut Workspace,
 2349        direction: SplitDirection,
 2350        window: &mut Window,
 2351        cx: &mut Context<Workspace>,
 2352    ) {
 2353        let project = workspace.project().clone();
 2354        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2355
 2356        cx.spawn_in(window, async move |workspace, cx| {
 2357            let buffer = create.await?;
 2358            workspace.update_in(cx, move |workspace, window, cx| {
 2359                workspace.split_item(
 2360                    direction,
 2361                    Box::new(
 2362                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2363                    ),
 2364                    window,
 2365                    cx,
 2366                )
 2367            })?;
 2368            anyhow::Ok(())
 2369        })
 2370        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2371            match e.error_code() {
 2372                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2373                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2374                e.error_tag("required").unwrap_or("the latest version")
 2375            )),
 2376                _ => None,
 2377            }
 2378        });
 2379    }
 2380
 2381    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2382        self.leader_id
 2383    }
 2384
 2385    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2386        &self.buffer
 2387    }
 2388
 2389    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2390        self.workspace.as_ref()?.0.upgrade()
 2391    }
 2392
 2393    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2394        self.buffer().read(cx).title(cx)
 2395    }
 2396
 2397    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2398        let git_blame_gutter_max_author_length = self
 2399            .render_git_blame_gutter(cx)
 2400            .then(|| {
 2401                if let Some(blame) = self.blame.as_ref() {
 2402                    let max_author_length =
 2403                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2404                    Some(max_author_length)
 2405                } else {
 2406                    None
 2407                }
 2408            })
 2409            .flatten();
 2410
 2411        EditorSnapshot {
 2412            mode: self.mode.clone(),
 2413            show_gutter: self.show_gutter,
 2414            show_line_numbers: self.show_line_numbers,
 2415            show_git_diff_gutter: self.show_git_diff_gutter,
 2416            show_code_actions: self.show_code_actions,
 2417            show_runnables: self.show_runnables,
 2418            show_breakpoints: self.show_breakpoints,
 2419            git_blame_gutter_max_author_length,
 2420            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2421            scroll_anchor: self.scroll_manager.anchor(),
 2422            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2423            placeholder_text: self.placeholder_text.clone(),
 2424            is_focused: self.focus_handle.is_focused(window),
 2425            current_line_highlight: self
 2426                .current_line_highlight
 2427                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2428            gutter_hovered: self.gutter_hovered,
 2429        }
 2430    }
 2431
 2432    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2433        self.buffer.read(cx).language_at(point, cx)
 2434    }
 2435
 2436    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2437        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2438    }
 2439
 2440    pub fn active_excerpt(
 2441        &self,
 2442        cx: &App,
 2443    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2444        self.buffer
 2445            .read(cx)
 2446            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2447    }
 2448
 2449    pub fn mode(&self) -> &EditorMode {
 2450        &self.mode
 2451    }
 2452
 2453    pub fn set_mode(&mut self, mode: EditorMode) {
 2454        self.mode = mode;
 2455    }
 2456
 2457    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2458        self.collaboration_hub.as_deref()
 2459    }
 2460
 2461    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2462        self.collaboration_hub = Some(hub);
 2463    }
 2464
 2465    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2466        self.in_project_search = in_project_search;
 2467    }
 2468
 2469    pub fn set_custom_context_menu(
 2470        &mut self,
 2471        f: impl 'static
 2472        + Fn(
 2473            &mut Self,
 2474            DisplayPoint,
 2475            &mut Window,
 2476            &mut Context<Self>,
 2477        ) -> Option<Entity<ui::ContextMenu>>,
 2478    ) {
 2479        self.custom_context_menu = Some(Box::new(f))
 2480    }
 2481
 2482    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2483        self.completion_provider = provider;
 2484    }
 2485
 2486    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2487        self.semantics_provider.clone()
 2488    }
 2489
 2490    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2491        self.semantics_provider = provider;
 2492    }
 2493
 2494    pub fn set_edit_prediction_provider<T>(
 2495        &mut self,
 2496        provider: Option<Entity<T>>,
 2497        window: &mut Window,
 2498        cx: &mut Context<Self>,
 2499    ) where
 2500        T: EditPredictionProvider,
 2501    {
 2502        self.edit_prediction_provider =
 2503            provider.map(|provider| RegisteredInlineCompletionProvider {
 2504                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2505                    if this.focus_handle.is_focused(window) {
 2506                        this.update_visible_inline_completion(window, cx);
 2507                    }
 2508                }),
 2509                provider: Arc::new(provider),
 2510            });
 2511        self.update_edit_prediction_settings(cx);
 2512        self.refresh_inline_completion(false, false, window, cx);
 2513    }
 2514
 2515    pub fn placeholder_text(&self) -> Option<&str> {
 2516        self.placeholder_text.as_deref()
 2517    }
 2518
 2519    pub fn set_placeholder_text(
 2520        &mut self,
 2521        placeholder_text: impl Into<Arc<str>>,
 2522        cx: &mut Context<Self>,
 2523    ) {
 2524        let placeholder_text = Some(placeholder_text.into());
 2525        if self.placeholder_text != placeholder_text {
 2526            self.placeholder_text = placeholder_text;
 2527            cx.notify();
 2528        }
 2529    }
 2530
 2531    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2532        self.cursor_shape = cursor_shape;
 2533
 2534        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2535        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2536
 2537        cx.notify();
 2538    }
 2539
 2540    pub fn set_current_line_highlight(
 2541        &mut self,
 2542        current_line_highlight: Option<CurrentLineHighlight>,
 2543    ) {
 2544        self.current_line_highlight = current_line_highlight;
 2545    }
 2546
 2547    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2548        self.collapse_matches = collapse_matches;
 2549    }
 2550
 2551    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2552        let buffers = self.buffer.read(cx).all_buffers();
 2553        let Some(project) = self.project.as_ref() else {
 2554            return;
 2555        };
 2556        project.update(cx, |project, cx| {
 2557            for buffer in buffers {
 2558                self.registered_buffers
 2559                    .entry(buffer.read(cx).remote_id())
 2560                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2561            }
 2562        })
 2563    }
 2564
 2565    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2566        if self.collapse_matches {
 2567            return range.start..range.start;
 2568        }
 2569        range.clone()
 2570    }
 2571
 2572    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2573        if self.display_map.read(cx).clip_at_line_ends != clip {
 2574            self.display_map
 2575                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2576        }
 2577    }
 2578
 2579    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2580        self.input_enabled = input_enabled;
 2581    }
 2582
 2583    pub fn set_inline_completions_hidden_for_vim_mode(
 2584        &mut self,
 2585        hidden: bool,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        if hidden != self.inline_completions_hidden_for_vim_mode {
 2590            self.inline_completions_hidden_for_vim_mode = hidden;
 2591            if hidden {
 2592                self.update_visible_inline_completion(window, cx);
 2593            } else {
 2594                self.refresh_inline_completion(true, false, window, cx);
 2595            }
 2596        }
 2597    }
 2598
 2599    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2600        self.menu_inline_completions_policy = value;
 2601    }
 2602
 2603    pub fn set_autoindent(&mut self, autoindent: bool) {
 2604        if autoindent {
 2605            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2606        } else {
 2607            self.autoindent_mode = None;
 2608        }
 2609    }
 2610
 2611    pub fn read_only(&self, cx: &App) -> bool {
 2612        self.read_only || self.buffer.read(cx).read_only()
 2613    }
 2614
 2615    pub fn set_read_only(&mut self, read_only: bool) {
 2616        self.read_only = read_only;
 2617    }
 2618
 2619    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2620        self.use_autoclose = autoclose;
 2621    }
 2622
 2623    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2624        self.use_auto_surround = auto_surround;
 2625    }
 2626
 2627    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2628        self.auto_replace_emoji_shortcode = auto_replace;
 2629    }
 2630
 2631    pub fn toggle_edit_predictions(
 2632        &mut self,
 2633        _: &ToggleEditPrediction,
 2634        window: &mut Window,
 2635        cx: &mut Context<Self>,
 2636    ) {
 2637        if self.show_inline_completions_override.is_some() {
 2638            self.set_show_edit_predictions(None, window, cx);
 2639        } else {
 2640            let show_edit_predictions = !self.edit_predictions_enabled();
 2641            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2642        }
 2643    }
 2644
 2645    pub fn set_show_edit_predictions(
 2646        &mut self,
 2647        show_edit_predictions: Option<bool>,
 2648        window: &mut Window,
 2649        cx: &mut Context<Self>,
 2650    ) {
 2651        self.show_inline_completions_override = show_edit_predictions;
 2652        self.update_edit_prediction_settings(cx);
 2653
 2654        if let Some(false) = show_edit_predictions {
 2655            self.discard_inline_completion(false, cx);
 2656        } else {
 2657            self.refresh_inline_completion(false, true, window, cx);
 2658        }
 2659    }
 2660
 2661    fn inline_completions_disabled_in_scope(
 2662        &self,
 2663        buffer: &Entity<Buffer>,
 2664        buffer_position: language::Anchor,
 2665        cx: &App,
 2666    ) -> bool {
 2667        let snapshot = buffer.read(cx).snapshot();
 2668        let settings = snapshot.settings_at(buffer_position, cx);
 2669
 2670        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2671            return false;
 2672        };
 2673
 2674        scope.override_name().map_or(false, |scope_name| {
 2675            settings
 2676                .edit_predictions_disabled_in
 2677                .iter()
 2678                .any(|s| s == scope_name)
 2679        })
 2680    }
 2681
 2682    pub fn set_use_modal_editing(&mut self, to: bool) {
 2683        self.use_modal_editing = to;
 2684    }
 2685
 2686    pub fn use_modal_editing(&self) -> bool {
 2687        self.use_modal_editing
 2688    }
 2689
 2690    fn selections_did_change(
 2691        &mut self,
 2692        local: bool,
 2693        old_cursor_position: &Anchor,
 2694        should_update_completions: bool,
 2695        window: &mut Window,
 2696        cx: &mut Context<Self>,
 2697    ) {
 2698        window.invalidate_character_coordinates();
 2699
 2700        // Copy selections to primary selection buffer
 2701        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2702        if local {
 2703            let selections = self.selections.all::<usize>(cx);
 2704            let buffer_handle = self.buffer.read(cx).read(cx);
 2705
 2706            let mut text = String::new();
 2707            for (index, selection) in selections.iter().enumerate() {
 2708                let text_for_selection = buffer_handle
 2709                    .text_for_range(selection.start..selection.end)
 2710                    .collect::<String>();
 2711
 2712                text.push_str(&text_for_selection);
 2713                if index != selections.len() - 1 {
 2714                    text.push('\n');
 2715                }
 2716            }
 2717
 2718            if !text.is_empty() {
 2719                cx.write_to_primary(ClipboardItem::new_string(text));
 2720            }
 2721        }
 2722
 2723        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2724            self.buffer.update(cx, |buffer, cx| {
 2725                buffer.set_active_selections(
 2726                    &self.selections.disjoint_anchors(),
 2727                    self.selections.line_mode,
 2728                    self.cursor_shape,
 2729                    cx,
 2730                )
 2731            });
 2732        }
 2733        let display_map = self
 2734            .display_map
 2735            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2736        let buffer = &display_map.buffer_snapshot;
 2737        if self.selections.count() == 1 {
 2738            self.add_selections_state = None;
 2739        }
 2740        self.select_next_state = None;
 2741        self.select_prev_state = None;
 2742        self.select_syntax_node_history.try_clear();
 2743        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2744        self.snippet_stack
 2745            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2746        self.take_rename(false, window, cx);
 2747
 2748        let newest_selection = self.selections.newest_anchor();
 2749        let new_cursor_position = newest_selection.head();
 2750        let selection_start = newest_selection.start;
 2751
 2752        self.push_to_nav_history(
 2753            *old_cursor_position,
 2754            Some(new_cursor_position.to_point(buffer)),
 2755            false,
 2756            cx,
 2757        );
 2758
 2759        if local {
 2760            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2761                if !self.registered_buffers.contains_key(&buffer_id) {
 2762                    if let Some(project) = self.project.as_ref() {
 2763                        project.update(cx, |project, cx| {
 2764                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2765                                return;
 2766                            };
 2767                            self.registered_buffers.insert(
 2768                                buffer_id,
 2769                                project.register_buffer_with_language_servers(&buffer, cx),
 2770                            );
 2771                        })
 2772                    }
 2773                }
 2774            }
 2775
 2776            let mut context_menu = self.context_menu.borrow_mut();
 2777            let completion_menu = match context_menu.as_ref() {
 2778                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2779                Some(CodeContextMenu::CodeActions(_)) => {
 2780                    *context_menu = None;
 2781                    None
 2782                }
 2783                None => None,
 2784            };
 2785            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2786            drop(context_menu);
 2787
 2788            if should_update_completions {
 2789                if let Some(completion_position) = completion_position {
 2790                    let start_offset = selection_start.to_offset(buffer);
 2791                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2792                    let continue_showing = if position_matches {
 2793                        if self.snippet_stack.is_empty() {
 2794                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2795                        } else {
 2796                            // Snippet choices can be shown even when the cursor is in whitespace.
 2797                            // Dismissing the menu when actions like backspace
 2798                            true
 2799                        }
 2800                    } else {
 2801                        false
 2802                    };
 2803
 2804                    if continue_showing {
 2805                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2806                    } else {
 2807                        self.hide_context_menu(window, cx);
 2808                    }
 2809                }
 2810            }
 2811
 2812            hide_hover(self, cx);
 2813
 2814            if old_cursor_position.to_display_point(&display_map).row()
 2815                != new_cursor_position.to_display_point(&display_map).row()
 2816            {
 2817                self.available_code_actions.take();
 2818            }
 2819            self.refresh_code_actions(window, cx);
 2820            self.refresh_document_highlights(cx);
 2821            self.refresh_selected_text_highlights(false, window, cx);
 2822            refresh_matching_bracket_highlights(self, window, cx);
 2823            self.update_visible_inline_completion(window, cx);
 2824            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2825            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2826            self.inline_blame_popover.take();
 2827            if self.git_blame_inline_enabled {
 2828                self.start_inline_blame_timer(window, cx);
 2829            }
 2830        }
 2831
 2832        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2833        cx.emit(EditorEvent::SelectionsChanged { local });
 2834
 2835        let selections = &self.selections.disjoint;
 2836        if selections.len() == 1 {
 2837            cx.emit(SearchEvent::ActiveMatchChanged)
 2838        }
 2839        if local {
 2840            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2841                let inmemory_selections = selections
 2842                    .iter()
 2843                    .map(|s| {
 2844                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2845                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2846                    })
 2847                    .collect();
 2848                self.update_restoration_data(cx, |data| {
 2849                    data.selections = inmemory_selections;
 2850                });
 2851
 2852                if WorkspaceSettings::get(None, cx).restore_on_startup
 2853                    != RestoreOnStartupBehavior::None
 2854                {
 2855                    if let Some(workspace_id) =
 2856                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2857                    {
 2858                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2859                        let selections = selections.clone();
 2860                        let background_executor = cx.background_executor().clone();
 2861                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2862                        self.serialize_selections = cx.background_spawn(async move {
 2863                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2864                    let db_selections = selections
 2865                        .iter()
 2866                        .map(|selection| {
 2867                            (
 2868                                selection.start.to_offset(&snapshot),
 2869                                selection.end.to_offset(&snapshot),
 2870                            )
 2871                        })
 2872                        .collect();
 2873
 2874                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2875                        .await
 2876                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2877                        .log_err();
 2878                });
 2879                    }
 2880                }
 2881            }
 2882        }
 2883
 2884        cx.notify();
 2885    }
 2886
 2887    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2888        use text::ToOffset as _;
 2889        use text::ToPoint as _;
 2890
 2891        if self.mode.is_minimap()
 2892            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2893        {
 2894            return;
 2895        }
 2896
 2897        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2898            return;
 2899        };
 2900
 2901        let snapshot = singleton.read(cx).snapshot();
 2902        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2903            let display_snapshot = display_map.snapshot(cx);
 2904
 2905            display_snapshot
 2906                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2907                .map(|fold| {
 2908                    fold.range.start.text_anchor.to_point(&snapshot)
 2909                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2910                })
 2911                .collect()
 2912        });
 2913        self.update_restoration_data(cx, |data| {
 2914            data.folds = inmemory_folds;
 2915        });
 2916
 2917        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2918            return;
 2919        };
 2920        let background_executor = cx.background_executor().clone();
 2921        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2922        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2923            display_map
 2924                .snapshot(cx)
 2925                .folds_in_range(0..snapshot.len())
 2926                .map(|fold| {
 2927                    (
 2928                        fold.range.start.text_anchor.to_offset(&snapshot),
 2929                        fold.range.end.text_anchor.to_offset(&snapshot),
 2930                    )
 2931                })
 2932                .collect()
 2933        });
 2934        self.serialize_folds = cx.background_spawn(async move {
 2935            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2936            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2937                .await
 2938                .with_context(|| {
 2939                    format!(
 2940                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2941                    )
 2942                })
 2943                .log_err();
 2944        });
 2945    }
 2946
 2947    pub fn sync_selections(
 2948        &mut self,
 2949        other: Entity<Editor>,
 2950        cx: &mut Context<Self>,
 2951    ) -> gpui::Subscription {
 2952        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2953        self.selections.change_with(cx, |selections| {
 2954            selections.select_anchors(other_selections);
 2955        });
 2956
 2957        let other_subscription =
 2958            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2959                EditorEvent::SelectionsChanged { local: true } => {
 2960                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2961                    if other_selections.is_empty() {
 2962                        return;
 2963                    }
 2964                    this.selections.change_with(cx, |selections| {
 2965                        selections.select_anchors(other_selections);
 2966                    });
 2967                }
 2968                _ => {}
 2969            });
 2970
 2971        let this_subscription =
 2972            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2973                EditorEvent::SelectionsChanged { local: true } => {
 2974                    let these_selections = this.selections.disjoint.to_vec();
 2975                    if these_selections.is_empty() {
 2976                        return;
 2977                    }
 2978                    other.update(cx, |other_editor, cx| {
 2979                        other_editor.selections.change_with(cx, |selections| {
 2980                            selections.select_anchors(these_selections);
 2981                        })
 2982                    });
 2983                }
 2984                _ => {}
 2985            });
 2986
 2987        Subscription::join(other_subscription, this_subscription)
 2988    }
 2989
 2990    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2991    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2992    /// effects of selection change occur at the end of the transaction.
 2993    pub fn change_selections<R>(
 2994        &mut self,
 2995        autoscroll: Option<Autoscroll>,
 2996        window: &mut Window,
 2997        cx: &mut Context<Self>,
 2998        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2999    ) -> R {
 3000        self.change_selections_inner(true, autoscroll, window, cx, change)
 3001    }
 3002
 3003    pub(crate) fn change_selections_without_updating_completions<R>(
 3004        &mut self,
 3005        autoscroll: Option<Autoscroll>,
 3006        window: &mut Window,
 3007        cx: &mut Context<Self>,
 3008        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3009    ) -> R {
 3010        self.change_selections_inner(false, autoscroll, window, cx, change)
 3011    }
 3012
 3013    fn change_selections_inner<R>(
 3014        &mut self,
 3015        should_update_completions: bool,
 3016        autoscroll: Option<Autoscroll>,
 3017        window: &mut Window,
 3018        cx: &mut Context<Self>,
 3019        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3020    ) -> R {
 3021        if let Some(state) = &mut self.deferred_selection_effects_state {
 3022            state.autoscroll = autoscroll.or(state.autoscroll);
 3023            state.should_update_completions = should_update_completions;
 3024            let (changed, result) = self.selections.change_with(cx, change);
 3025            state.changed |= changed;
 3026            return result;
 3027        }
 3028        let mut state = DeferredSelectionEffectsState {
 3029            changed: false,
 3030            should_update_completions,
 3031            autoscroll,
 3032            old_cursor_position: self.selections.newest_anchor().head(),
 3033            history_entry: SelectionHistoryEntry {
 3034                selections: self.selections.disjoint_anchors(),
 3035                select_next_state: self.select_next_state.clone(),
 3036                select_prev_state: self.select_prev_state.clone(),
 3037                add_selections_state: self.add_selections_state.clone(),
 3038            },
 3039        };
 3040        let (changed, result) = self.selections.change_with(cx, change);
 3041        state.changed = state.changed || changed;
 3042        if self.defer_selection_effects {
 3043            self.deferred_selection_effects_state = Some(state);
 3044        } else {
 3045            self.apply_selection_effects(state, window, cx);
 3046        }
 3047        result
 3048    }
 3049
 3050    /// Defers the effects of selection change, so that the effects of multiple calls to
 3051    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3052    /// to selection history and the state of popovers based on selection position aren't
 3053    /// erroneously updated.
 3054    pub fn with_selection_effects_deferred<R>(
 3055        &mut self,
 3056        window: &mut Window,
 3057        cx: &mut Context<Self>,
 3058        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3059    ) -> R {
 3060        let already_deferred = self.defer_selection_effects;
 3061        self.defer_selection_effects = true;
 3062        let result = update(self, window, cx);
 3063        if !already_deferred {
 3064            self.defer_selection_effects = false;
 3065            if let Some(state) = self.deferred_selection_effects_state.take() {
 3066                self.apply_selection_effects(state, window, cx);
 3067            }
 3068        }
 3069        result
 3070    }
 3071
 3072    fn apply_selection_effects(
 3073        &mut self,
 3074        state: DeferredSelectionEffectsState,
 3075        window: &mut Window,
 3076        cx: &mut Context<Self>,
 3077    ) {
 3078        if state.changed {
 3079            self.selection_history.push(state.history_entry);
 3080
 3081            if let Some(autoscroll) = state.autoscroll {
 3082                self.request_autoscroll(autoscroll, cx);
 3083            }
 3084
 3085            let old_cursor_position = &state.old_cursor_position;
 3086
 3087            self.selections_did_change(
 3088                true,
 3089                &old_cursor_position,
 3090                state.should_update_completions,
 3091                window,
 3092                cx,
 3093            );
 3094
 3095            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3096                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3097            }
 3098        }
 3099    }
 3100
 3101    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3102    where
 3103        I: IntoIterator<Item = (Range<S>, T)>,
 3104        S: ToOffset,
 3105        T: Into<Arc<str>>,
 3106    {
 3107        if self.read_only(cx) {
 3108            return;
 3109        }
 3110
 3111        self.buffer
 3112            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3113    }
 3114
 3115    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3116    where
 3117        I: IntoIterator<Item = (Range<S>, T)>,
 3118        S: ToOffset,
 3119        T: Into<Arc<str>>,
 3120    {
 3121        if self.read_only(cx) {
 3122            return;
 3123        }
 3124
 3125        self.buffer.update(cx, |buffer, cx| {
 3126            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3127        });
 3128    }
 3129
 3130    pub fn edit_with_block_indent<I, S, T>(
 3131        &mut self,
 3132        edits: I,
 3133        original_indent_columns: Vec<Option<u32>>,
 3134        cx: &mut Context<Self>,
 3135    ) where
 3136        I: IntoIterator<Item = (Range<S>, T)>,
 3137        S: ToOffset,
 3138        T: Into<Arc<str>>,
 3139    {
 3140        if self.read_only(cx) {
 3141            return;
 3142        }
 3143
 3144        self.buffer.update(cx, |buffer, cx| {
 3145            buffer.edit(
 3146                edits,
 3147                Some(AutoindentMode::Block {
 3148                    original_indent_columns,
 3149                }),
 3150                cx,
 3151            )
 3152        });
 3153    }
 3154
 3155    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3156        self.hide_context_menu(window, cx);
 3157
 3158        match phase {
 3159            SelectPhase::Begin {
 3160                position,
 3161                add,
 3162                click_count,
 3163            } => self.begin_selection(position, add, click_count, window, cx),
 3164            SelectPhase::BeginColumnar {
 3165                position,
 3166                goal_column,
 3167                reset,
 3168            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3169            SelectPhase::Extend {
 3170                position,
 3171                click_count,
 3172            } => self.extend_selection(position, click_count, window, cx),
 3173            SelectPhase::Update {
 3174                position,
 3175                goal_column,
 3176                scroll_delta,
 3177            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3178            SelectPhase::End => self.end_selection(window, cx),
 3179        }
 3180    }
 3181
 3182    fn extend_selection(
 3183        &mut self,
 3184        position: DisplayPoint,
 3185        click_count: usize,
 3186        window: &mut Window,
 3187        cx: &mut Context<Self>,
 3188    ) {
 3189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3190        let tail = self.selections.newest::<usize>(cx).tail();
 3191        self.begin_selection(position, false, click_count, window, cx);
 3192
 3193        let position = position.to_offset(&display_map, Bias::Left);
 3194        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3195
 3196        let mut pending_selection = self
 3197            .selections
 3198            .pending_anchor()
 3199            .expect("extend_selection not called with pending selection");
 3200        if position >= tail {
 3201            pending_selection.start = tail_anchor;
 3202        } else {
 3203            pending_selection.end = tail_anchor;
 3204            pending_selection.reversed = true;
 3205        }
 3206
 3207        let mut pending_mode = self.selections.pending_mode().unwrap();
 3208        match &mut pending_mode {
 3209            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3210            _ => {}
 3211        }
 3212
 3213        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3214
 3215        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3216            s.set_pending(pending_selection, pending_mode)
 3217        });
 3218    }
 3219
 3220    fn begin_selection(
 3221        &mut self,
 3222        position: DisplayPoint,
 3223        add: bool,
 3224        click_count: usize,
 3225        window: &mut Window,
 3226        cx: &mut Context<Self>,
 3227    ) {
 3228        if !self.focus_handle.is_focused(window) {
 3229            self.last_focused_descendant = None;
 3230            window.focus(&self.focus_handle);
 3231        }
 3232
 3233        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3234        let buffer = &display_map.buffer_snapshot;
 3235        let position = display_map.clip_point(position, Bias::Left);
 3236
 3237        let start;
 3238        let end;
 3239        let mode;
 3240        let mut auto_scroll;
 3241        match click_count {
 3242            1 => {
 3243                start = buffer.anchor_before(position.to_point(&display_map));
 3244                end = start;
 3245                mode = SelectMode::Character;
 3246                auto_scroll = true;
 3247            }
 3248            2 => {
 3249                let range = movement::surrounding_word(&display_map, position);
 3250                start = buffer.anchor_before(range.start.to_point(&display_map));
 3251                end = buffer.anchor_before(range.end.to_point(&display_map));
 3252                mode = SelectMode::Word(start..end);
 3253                auto_scroll = true;
 3254            }
 3255            3 => {
 3256                let position = display_map
 3257                    .clip_point(position, Bias::Left)
 3258                    .to_point(&display_map);
 3259                let line_start = display_map.prev_line_boundary(position).0;
 3260                let next_line_start = buffer.clip_point(
 3261                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3262                    Bias::Left,
 3263                );
 3264                start = buffer.anchor_before(line_start);
 3265                end = buffer.anchor_before(next_line_start);
 3266                mode = SelectMode::Line(start..end);
 3267                auto_scroll = true;
 3268            }
 3269            _ => {
 3270                start = buffer.anchor_before(0);
 3271                end = buffer.anchor_before(buffer.len());
 3272                mode = SelectMode::All;
 3273                auto_scroll = false;
 3274            }
 3275        }
 3276        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3277
 3278        let point_to_delete: Option<usize> = {
 3279            let selected_points: Vec<Selection<Point>> =
 3280                self.selections.disjoint_in_range(start..end, cx);
 3281
 3282            if !add || click_count > 1 {
 3283                None
 3284            } else if !selected_points.is_empty() {
 3285                Some(selected_points[0].id)
 3286            } else {
 3287                let clicked_point_already_selected =
 3288                    self.selections.disjoint.iter().find(|selection| {
 3289                        selection.start.to_point(buffer) == start.to_point(buffer)
 3290                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3291                    });
 3292
 3293                clicked_point_already_selected.map(|selection| selection.id)
 3294            }
 3295        };
 3296
 3297        let selections_count = self.selections.count();
 3298
 3299        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3300            if let Some(point_to_delete) = point_to_delete {
 3301                s.delete(point_to_delete);
 3302
 3303                if selections_count == 1 {
 3304                    s.set_pending_anchor_range(start..end, mode);
 3305                }
 3306            } else {
 3307                if !add {
 3308                    s.clear_disjoint();
 3309                }
 3310
 3311                s.set_pending_anchor_range(start..end, mode);
 3312            }
 3313        });
 3314    }
 3315
 3316    fn begin_columnar_selection(
 3317        &mut self,
 3318        position: DisplayPoint,
 3319        goal_column: u32,
 3320        reset: bool,
 3321        window: &mut Window,
 3322        cx: &mut Context<Self>,
 3323    ) {
 3324        if !self.focus_handle.is_focused(window) {
 3325            self.last_focused_descendant = None;
 3326            window.focus(&self.focus_handle);
 3327        }
 3328
 3329        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3330
 3331        if reset {
 3332            let pointer_position = display_map
 3333                .buffer_snapshot
 3334                .anchor_before(position.to_point(&display_map));
 3335
 3336            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3337                s.clear_disjoint();
 3338                s.set_pending_anchor_range(
 3339                    pointer_position..pointer_position,
 3340                    SelectMode::Character,
 3341                );
 3342            });
 3343            if position.column() != goal_column {
 3344                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3345            } else {
 3346                self.columnar_display_point = None;
 3347            }
 3348        }
 3349
 3350        let tail = self.selections.newest::<Point>(cx).tail();
 3351        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3352
 3353        if !reset {
 3354            self.columnar_display_point = None;
 3355            self.select_columns(
 3356                tail.to_display_point(&display_map),
 3357                position,
 3358                goal_column,
 3359                &display_map,
 3360                window,
 3361                cx,
 3362            );
 3363        }
 3364    }
 3365
 3366    fn update_selection(
 3367        &mut self,
 3368        position: DisplayPoint,
 3369        goal_column: u32,
 3370        scroll_delta: gpui::Point<f32>,
 3371        window: &mut Window,
 3372        cx: &mut Context<Self>,
 3373    ) {
 3374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3375
 3376        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3377            let tail = self
 3378                .columnar_display_point
 3379                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3380            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3381        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3382            let buffer = self.buffer.read(cx).snapshot(cx);
 3383            let head;
 3384            let tail;
 3385            let mode = self.selections.pending_mode().unwrap();
 3386            match &mode {
 3387                SelectMode::Character => {
 3388                    head = position.to_point(&display_map);
 3389                    tail = pending.tail().to_point(&buffer);
 3390                }
 3391                SelectMode::Word(original_range) => {
 3392                    let original_display_range = original_range.start.to_display_point(&display_map)
 3393                        ..original_range.end.to_display_point(&display_map);
 3394                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3395                        ..original_display_range.end.to_point(&display_map);
 3396                    if movement::is_inside_word(&display_map, position)
 3397                        || original_display_range.contains(&position)
 3398                    {
 3399                        let word_range = movement::surrounding_word(&display_map, position);
 3400                        if word_range.start < original_display_range.start {
 3401                            head = word_range.start.to_point(&display_map);
 3402                        } else {
 3403                            head = word_range.end.to_point(&display_map);
 3404                        }
 3405                    } else {
 3406                        head = position.to_point(&display_map);
 3407                    }
 3408
 3409                    if head <= original_buffer_range.start {
 3410                        tail = original_buffer_range.end;
 3411                    } else {
 3412                        tail = original_buffer_range.start;
 3413                    }
 3414                }
 3415                SelectMode::Line(original_range) => {
 3416                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3417
 3418                    let position = display_map
 3419                        .clip_point(position, Bias::Left)
 3420                        .to_point(&display_map);
 3421                    let line_start = display_map.prev_line_boundary(position).0;
 3422                    let next_line_start = buffer.clip_point(
 3423                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3424                        Bias::Left,
 3425                    );
 3426
 3427                    if line_start < original_range.start {
 3428                        head = line_start
 3429                    } else {
 3430                        head = next_line_start
 3431                    }
 3432
 3433                    if head <= original_range.start {
 3434                        tail = original_range.end;
 3435                    } else {
 3436                        tail = original_range.start;
 3437                    }
 3438                }
 3439                SelectMode::All => {
 3440                    return;
 3441                }
 3442            };
 3443
 3444            if head < tail {
 3445                pending.start = buffer.anchor_before(head);
 3446                pending.end = buffer.anchor_before(tail);
 3447                pending.reversed = true;
 3448            } else {
 3449                pending.start = buffer.anchor_before(tail);
 3450                pending.end = buffer.anchor_before(head);
 3451                pending.reversed = false;
 3452            }
 3453
 3454            self.change_selections(None, window, cx, |s| {
 3455                s.set_pending(pending, mode);
 3456            });
 3457        } else {
 3458            log::error!("update_selection dispatched with no pending selection");
 3459            return;
 3460        }
 3461
 3462        self.apply_scroll_delta(scroll_delta, window, cx);
 3463        cx.notify();
 3464    }
 3465
 3466    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3467        self.columnar_selection_tail.take();
 3468        if self.selections.pending_anchor().is_some() {
 3469            let selections = self.selections.all::<usize>(cx);
 3470            self.change_selections(None, window, cx, |s| {
 3471                s.select(selections);
 3472                s.clear_pending();
 3473            });
 3474        }
 3475    }
 3476
 3477    fn select_columns(
 3478        &mut self,
 3479        tail: DisplayPoint,
 3480        head: DisplayPoint,
 3481        goal_column: u32,
 3482        display_map: &DisplaySnapshot,
 3483        window: &mut Window,
 3484        cx: &mut Context<Self>,
 3485    ) {
 3486        let start_row = cmp::min(tail.row(), head.row());
 3487        let end_row = cmp::max(tail.row(), head.row());
 3488        let start_column = cmp::min(tail.column(), goal_column);
 3489        let end_column = cmp::max(tail.column(), goal_column);
 3490        let reversed = start_column < tail.column();
 3491
 3492        let selection_ranges = (start_row.0..=end_row.0)
 3493            .map(DisplayRow)
 3494            .filter_map(|row| {
 3495                if !display_map.is_block_line(row) {
 3496                    let start = display_map
 3497                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3498                        .to_point(display_map);
 3499                    let end = display_map
 3500                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3501                        .to_point(display_map);
 3502                    if reversed {
 3503                        Some(end..start)
 3504                    } else {
 3505                        Some(start..end)
 3506                    }
 3507                } else {
 3508                    None
 3509                }
 3510            })
 3511            .collect::<Vec<_>>();
 3512
 3513        let mut non_empty_ranges = selection_ranges
 3514            .iter()
 3515            .filter(|selection_range| selection_range.start != selection_range.end)
 3516            .peekable();
 3517
 3518        let ranges = if non_empty_ranges.peek().is_some() {
 3519            non_empty_ranges.cloned().collect()
 3520        } else {
 3521            selection_ranges
 3522        };
 3523
 3524        self.change_selections(None, window, cx, |s| {
 3525            s.select_ranges(ranges);
 3526        });
 3527        cx.notify();
 3528    }
 3529
 3530    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3531        self.selections
 3532            .all_adjusted(cx)
 3533            .iter()
 3534            .any(|selection| !selection.is_empty())
 3535    }
 3536
 3537    pub fn has_pending_nonempty_selection(&self) -> bool {
 3538        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3539            Some(Selection { start, end, .. }) => start != end,
 3540            None => false,
 3541        };
 3542
 3543        pending_nonempty_selection
 3544            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3545    }
 3546
 3547    pub fn has_pending_selection(&self) -> bool {
 3548        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3549    }
 3550
 3551    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3552        self.selection_mark_mode = false;
 3553        self.selection_drag_state = SelectionDragState::None;
 3554
 3555        if self.clear_expanded_diff_hunks(cx) {
 3556            cx.notify();
 3557            return;
 3558        }
 3559        if self.dismiss_menus_and_popups(true, window, cx) {
 3560            return;
 3561        }
 3562
 3563        if self.mode.is_full()
 3564            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3565        {
 3566            return;
 3567        }
 3568
 3569        cx.propagate();
 3570    }
 3571
 3572    pub fn dismiss_menus_and_popups(
 3573        &mut self,
 3574        is_user_requested: bool,
 3575        window: &mut Window,
 3576        cx: &mut Context<Self>,
 3577    ) -> bool {
 3578        if self.take_rename(false, window, cx).is_some() {
 3579            return true;
 3580        }
 3581
 3582        if hide_hover(self, cx) {
 3583            return true;
 3584        }
 3585
 3586        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3587            return true;
 3588        }
 3589
 3590        if self.hide_context_menu(window, cx).is_some() {
 3591            return true;
 3592        }
 3593
 3594        if self.mouse_context_menu.take().is_some() {
 3595            return true;
 3596        }
 3597
 3598        if is_user_requested && self.discard_inline_completion(true, cx) {
 3599            return true;
 3600        }
 3601
 3602        if self.snippet_stack.pop().is_some() {
 3603            return true;
 3604        }
 3605
 3606        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3607            self.dismiss_diagnostics(cx);
 3608            return true;
 3609        }
 3610
 3611        false
 3612    }
 3613
 3614    fn linked_editing_ranges_for(
 3615        &self,
 3616        selection: Range<text::Anchor>,
 3617        cx: &App,
 3618    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3619        if self.linked_edit_ranges.is_empty() {
 3620            return None;
 3621        }
 3622        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3623            selection.end.buffer_id.and_then(|end_buffer_id| {
 3624                if selection.start.buffer_id != Some(end_buffer_id) {
 3625                    return None;
 3626                }
 3627                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3628                let snapshot = buffer.read(cx).snapshot();
 3629                self.linked_edit_ranges
 3630                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3631                    .map(|ranges| (ranges, snapshot, buffer))
 3632            })?;
 3633        use text::ToOffset as TO;
 3634        // find offset from the start of current range to current cursor position
 3635        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3636
 3637        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3638        let start_difference = start_offset - start_byte_offset;
 3639        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3640        let end_difference = end_offset - start_byte_offset;
 3641        // Current range has associated linked ranges.
 3642        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3643        for range in linked_ranges.iter() {
 3644            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3645            let end_offset = start_offset + end_difference;
 3646            let start_offset = start_offset + start_difference;
 3647            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3648                continue;
 3649            }
 3650            if self.selections.disjoint_anchor_ranges().any(|s| {
 3651                if s.start.buffer_id != selection.start.buffer_id
 3652                    || s.end.buffer_id != selection.end.buffer_id
 3653                {
 3654                    return false;
 3655                }
 3656                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3657                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3658            }) {
 3659                continue;
 3660            }
 3661            let start = buffer_snapshot.anchor_after(start_offset);
 3662            let end = buffer_snapshot.anchor_after(end_offset);
 3663            linked_edits
 3664                .entry(buffer.clone())
 3665                .or_default()
 3666                .push(start..end);
 3667        }
 3668        Some(linked_edits)
 3669    }
 3670
 3671    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3672        let text: Arc<str> = text.into();
 3673
 3674        if self.read_only(cx) {
 3675            return;
 3676        }
 3677
 3678        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3679
 3680        let selections = self.selections.all_adjusted(cx);
 3681        let mut bracket_inserted = false;
 3682        let mut edits = Vec::new();
 3683        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3684        let mut new_selections = Vec::with_capacity(selections.len());
 3685        let mut new_autoclose_regions = Vec::new();
 3686        let snapshot = self.buffer.read(cx).read(cx);
 3687        let mut clear_linked_edit_ranges = false;
 3688
 3689        for (selection, autoclose_region) in
 3690            self.selections_with_autoclose_regions(selections, &snapshot)
 3691        {
 3692            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3693                // Determine if the inserted text matches the opening or closing
 3694                // bracket of any of this language's bracket pairs.
 3695                let mut bracket_pair = None;
 3696                let mut is_bracket_pair_start = false;
 3697                let mut is_bracket_pair_end = false;
 3698                if !text.is_empty() {
 3699                    let mut bracket_pair_matching_end = None;
 3700                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3701                    //  and they are removing the character that triggered IME popup.
 3702                    for (pair, enabled) in scope.brackets() {
 3703                        if !pair.close && !pair.surround {
 3704                            continue;
 3705                        }
 3706
 3707                        if enabled && pair.start.ends_with(text.as_ref()) {
 3708                            let prefix_len = pair.start.len() - text.len();
 3709                            let preceding_text_matches_prefix = prefix_len == 0
 3710                                || (selection.start.column >= (prefix_len as u32)
 3711                                    && snapshot.contains_str_at(
 3712                                        Point::new(
 3713                                            selection.start.row,
 3714                                            selection.start.column - (prefix_len as u32),
 3715                                        ),
 3716                                        &pair.start[..prefix_len],
 3717                                    ));
 3718                            if preceding_text_matches_prefix {
 3719                                bracket_pair = Some(pair.clone());
 3720                                is_bracket_pair_start = true;
 3721                                break;
 3722                            }
 3723                        }
 3724                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3725                        {
 3726                            // take first bracket pair matching end, but don't break in case a later bracket
 3727                            // pair matches start
 3728                            bracket_pair_matching_end = Some(pair.clone());
 3729                        }
 3730                    }
 3731                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3732                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3733                        is_bracket_pair_end = true;
 3734                    }
 3735                }
 3736
 3737                if let Some(bracket_pair) = bracket_pair {
 3738                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3739                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3740                    let auto_surround =
 3741                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3742                    if selection.is_empty() {
 3743                        if is_bracket_pair_start {
 3744                            // If the inserted text is a suffix of an opening bracket and the
 3745                            // selection is preceded by the rest of the opening bracket, then
 3746                            // insert the closing bracket.
 3747                            let following_text_allows_autoclose = snapshot
 3748                                .chars_at(selection.start)
 3749                                .next()
 3750                                .map_or(true, |c| scope.should_autoclose_before(c));
 3751
 3752                            let preceding_text_allows_autoclose = selection.start.column == 0
 3753                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3754                                    true,
 3755                                    |c| {
 3756                                        bracket_pair.start != bracket_pair.end
 3757                                            || !snapshot
 3758                                                .char_classifier_at(selection.start)
 3759                                                .is_word(c)
 3760                                    },
 3761                                );
 3762
 3763                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3764                                && bracket_pair.start.len() == 1
 3765                            {
 3766                                let target = bracket_pair.start.chars().next().unwrap();
 3767                                let current_line_count = snapshot
 3768                                    .reversed_chars_at(selection.start)
 3769                                    .take_while(|&c| c != '\n')
 3770                                    .filter(|&c| c == target)
 3771                                    .count();
 3772                                current_line_count % 2 == 1
 3773                            } else {
 3774                                false
 3775                            };
 3776
 3777                            if autoclose
 3778                                && bracket_pair.close
 3779                                && following_text_allows_autoclose
 3780                                && preceding_text_allows_autoclose
 3781                                && !is_closing_quote
 3782                            {
 3783                                let anchor = snapshot.anchor_before(selection.end);
 3784                                new_selections.push((selection.map(|_| anchor), text.len()));
 3785                                new_autoclose_regions.push((
 3786                                    anchor,
 3787                                    text.len(),
 3788                                    selection.id,
 3789                                    bracket_pair.clone(),
 3790                                ));
 3791                                edits.push((
 3792                                    selection.range(),
 3793                                    format!("{}{}", text, bracket_pair.end).into(),
 3794                                ));
 3795                                bracket_inserted = true;
 3796                                continue;
 3797                            }
 3798                        }
 3799
 3800                        if let Some(region) = autoclose_region {
 3801                            // If the selection is followed by an auto-inserted closing bracket,
 3802                            // then don't insert that closing bracket again; just move the selection
 3803                            // past the closing bracket.
 3804                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3805                                && text.as_ref() == region.pair.end.as_str();
 3806                            if should_skip {
 3807                                let anchor = snapshot.anchor_after(selection.end);
 3808                                new_selections
 3809                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3810                                continue;
 3811                            }
 3812                        }
 3813
 3814                        let always_treat_brackets_as_autoclosed = snapshot
 3815                            .language_settings_at(selection.start, cx)
 3816                            .always_treat_brackets_as_autoclosed;
 3817                        if always_treat_brackets_as_autoclosed
 3818                            && is_bracket_pair_end
 3819                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3820                        {
 3821                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3822                            // and the inserted text is a closing bracket and the selection is followed
 3823                            // by the closing bracket then move the selection past the closing bracket.
 3824                            let anchor = snapshot.anchor_after(selection.end);
 3825                            new_selections.push((selection.map(|_| anchor), text.len()));
 3826                            continue;
 3827                        }
 3828                    }
 3829                    // If an opening bracket is 1 character long and is typed while
 3830                    // text is selected, then surround that text with the bracket pair.
 3831                    else if auto_surround
 3832                        && bracket_pair.surround
 3833                        && is_bracket_pair_start
 3834                        && bracket_pair.start.chars().count() == 1
 3835                    {
 3836                        edits.push((selection.start..selection.start, text.clone()));
 3837                        edits.push((
 3838                            selection.end..selection.end,
 3839                            bracket_pair.end.as_str().into(),
 3840                        ));
 3841                        bracket_inserted = true;
 3842                        new_selections.push((
 3843                            Selection {
 3844                                id: selection.id,
 3845                                start: snapshot.anchor_after(selection.start),
 3846                                end: snapshot.anchor_before(selection.end),
 3847                                reversed: selection.reversed,
 3848                                goal: selection.goal,
 3849                            },
 3850                            0,
 3851                        ));
 3852                        continue;
 3853                    }
 3854                }
 3855            }
 3856
 3857            if self.auto_replace_emoji_shortcode
 3858                && selection.is_empty()
 3859                && text.as_ref().ends_with(':')
 3860            {
 3861                if let Some(possible_emoji_short_code) =
 3862                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3863                {
 3864                    if !possible_emoji_short_code.is_empty() {
 3865                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3866                            let emoji_shortcode_start = Point::new(
 3867                                selection.start.row,
 3868                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3869                            );
 3870
 3871                            // Remove shortcode from buffer
 3872                            edits.push((
 3873                                emoji_shortcode_start..selection.start,
 3874                                "".to_string().into(),
 3875                            ));
 3876                            new_selections.push((
 3877                                Selection {
 3878                                    id: selection.id,
 3879                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3880                                    end: snapshot.anchor_before(selection.start),
 3881                                    reversed: selection.reversed,
 3882                                    goal: selection.goal,
 3883                                },
 3884                                0,
 3885                            ));
 3886
 3887                            // Insert emoji
 3888                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3889                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3890                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3891
 3892                            continue;
 3893                        }
 3894                    }
 3895                }
 3896            }
 3897
 3898            // If not handling any auto-close operation, then just replace the selected
 3899            // text with the given input and move the selection to the end of the
 3900            // newly inserted text.
 3901            let anchor = snapshot.anchor_after(selection.end);
 3902            if !self.linked_edit_ranges.is_empty() {
 3903                let start_anchor = snapshot.anchor_before(selection.start);
 3904
 3905                let is_word_char = text.chars().next().map_or(true, |char| {
 3906                    let classifier = snapshot
 3907                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3908                        .ignore_punctuation(true);
 3909                    classifier.is_word(char)
 3910                });
 3911
 3912                if is_word_char {
 3913                    if let Some(ranges) = self
 3914                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3915                    {
 3916                        for (buffer, edits) in ranges {
 3917                            linked_edits
 3918                                .entry(buffer.clone())
 3919                                .or_default()
 3920                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3921                        }
 3922                    }
 3923                } else {
 3924                    clear_linked_edit_ranges = true;
 3925                }
 3926            }
 3927
 3928            new_selections.push((selection.map(|_| anchor), 0));
 3929            edits.push((selection.start..selection.end, text.clone()));
 3930        }
 3931
 3932        drop(snapshot);
 3933
 3934        self.transact(window, cx, |this, window, cx| {
 3935            if clear_linked_edit_ranges {
 3936                this.linked_edit_ranges.clear();
 3937            }
 3938            let initial_buffer_versions =
 3939                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3940
 3941            this.buffer.update(cx, |buffer, cx| {
 3942                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3943            });
 3944            for (buffer, edits) in linked_edits {
 3945                buffer.update(cx, |buffer, cx| {
 3946                    let snapshot = buffer.snapshot();
 3947                    let edits = edits
 3948                        .into_iter()
 3949                        .map(|(range, text)| {
 3950                            use text::ToPoint as TP;
 3951                            let end_point = TP::to_point(&range.end, &snapshot);
 3952                            let start_point = TP::to_point(&range.start, &snapshot);
 3953                            (start_point..end_point, text)
 3954                        })
 3955                        .sorted_by_key(|(range, _)| range.start);
 3956                    buffer.edit(edits, None, cx);
 3957                })
 3958            }
 3959            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3960            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3961            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3962            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3963                .zip(new_selection_deltas)
 3964                .map(|(selection, delta)| Selection {
 3965                    id: selection.id,
 3966                    start: selection.start + delta,
 3967                    end: selection.end + delta,
 3968                    reversed: selection.reversed,
 3969                    goal: SelectionGoal::None,
 3970                })
 3971                .collect::<Vec<_>>();
 3972
 3973            let mut i = 0;
 3974            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3975                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3976                let start = map.buffer_snapshot.anchor_before(position);
 3977                let end = map.buffer_snapshot.anchor_after(position);
 3978                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3979                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3980                        Ordering::Less => i += 1,
 3981                        Ordering::Greater => break,
 3982                        Ordering::Equal => {
 3983                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3984                                Ordering::Less => i += 1,
 3985                                Ordering::Equal => break,
 3986                                Ordering::Greater => break,
 3987                            }
 3988                        }
 3989                    }
 3990                }
 3991                this.autoclose_regions.insert(
 3992                    i,
 3993                    AutocloseRegion {
 3994                        selection_id,
 3995                        range: start..end,
 3996                        pair,
 3997                    },
 3998                );
 3999            }
 4000
 4001            let had_active_inline_completion = this.has_active_inline_completion();
 4002            this.change_selections_without_updating_completions(
 4003                Some(Autoscroll::fit()),
 4004                window,
 4005                cx,
 4006                |s| s.select(new_selections),
 4007            );
 4008
 4009            if !bracket_inserted {
 4010                if let Some(on_type_format_task) =
 4011                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4012                {
 4013                    on_type_format_task.detach_and_log_err(cx);
 4014                }
 4015            }
 4016
 4017            let editor_settings = EditorSettings::get_global(cx);
 4018            if bracket_inserted
 4019                && (editor_settings.auto_signature_help
 4020                    || editor_settings.show_signature_help_after_edits)
 4021            {
 4022                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4023            }
 4024
 4025            let trigger_in_words =
 4026                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4027            if this.hard_wrap.is_some() {
 4028                let latest: Range<Point> = this.selections.newest(cx).range();
 4029                if latest.is_empty()
 4030                    && this
 4031                        .buffer()
 4032                        .read(cx)
 4033                        .snapshot(cx)
 4034                        .line_len(MultiBufferRow(latest.start.row))
 4035                        == latest.start.column
 4036                {
 4037                    this.rewrap_impl(
 4038                        RewrapOptions {
 4039                            override_language_settings: true,
 4040                            preserve_existing_whitespace: true,
 4041                        },
 4042                        cx,
 4043                    )
 4044                }
 4045            }
 4046            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4047            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4048            this.refresh_inline_completion(true, false, window, cx);
 4049            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4050        });
 4051    }
 4052
 4053    fn find_possible_emoji_shortcode_at_position(
 4054        snapshot: &MultiBufferSnapshot,
 4055        position: Point,
 4056    ) -> Option<String> {
 4057        let mut chars = Vec::new();
 4058        let mut found_colon = false;
 4059        for char in snapshot.reversed_chars_at(position).take(100) {
 4060            // Found a possible emoji shortcode in the middle of the buffer
 4061            if found_colon {
 4062                if char.is_whitespace() {
 4063                    chars.reverse();
 4064                    return Some(chars.iter().collect());
 4065                }
 4066                // If the previous character is not a whitespace, we are in the middle of a word
 4067                // and we only want to complete the shortcode if the word is made up of other emojis
 4068                let mut containing_word = String::new();
 4069                for ch in snapshot
 4070                    .reversed_chars_at(position)
 4071                    .skip(chars.len() + 1)
 4072                    .take(100)
 4073                {
 4074                    if ch.is_whitespace() {
 4075                        break;
 4076                    }
 4077                    containing_word.push(ch);
 4078                }
 4079                let containing_word = containing_word.chars().rev().collect::<String>();
 4080                if util::word_consists_of_emojis(containing_word.as_str()) {
 4081                    chars.reverse();
 4082                    return Some(chars.iter().collect());
 4083                }
 4084            }
 4085
 4086            if char.is_whitespace() || !char.is_ascii() {
 4087                return None;
 4088            }
 4089            if char == ':' {
 4090                found_colon = true;
 4091            } else {
 4092                chars.push(char);
 4093            }
 4094        }
 4095        // Found a possible emoji shortcode at the beginning of the buffer
 4096        chars.reverse();
 4097        Some(chars.iter().collect())
 4098    }
 4099
 4100    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4101        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4102        self.transact(window, cx, |this, window, cx| {
 4103            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4104                let selections = this.selections.all::<usize>(cx);
 4105                let multi_buffer = this.buffer.read(cx);
 4106                let buffer = multi_buffer.snapshot(cx);
 4107                selections
 4108                    .iter()
 4109                    .map(|selection| {
 4110                        let start_point = selection.start.to_point(&buffer);
 4111                        let mut existing_indent =
 4112                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4113                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4114                        let start = selection.start;
 4115                        let end = selection.end;
 4116                        let selection_is_empty = start == end;
 4117                        let language_scope = buffer.language_scope_at(start);
 4118                        let (
 4119                            comment_delimiter,
 4120                            doc_delimiter,
 4121                            insert_extra_newline,
 4122                            indent_on_newline,
 4123                            indent_on_extra_newline,
 4124                        ) = if let Some(language) = &language_scope {
 4125                            let mut insert_extra_newline =
 4126                                insert_extra_newline_brackets(&buffer, start..end, language)
 4127                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4128
 4129                            // Comment extension on newline is allowed only for cursor selections
 4130                            let comment_delimiter = maybe!({
 4131                                if !selection_is_empty {
 4132                                    return None;
 4133                                }
 4134
 4135                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4136                                    return None;
 4137                                }
 4138
 4139                                let delimiters = language.line_comment_prefixes();
 4140                                let max_len_of_delimiter =
 4141                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4142                                let (snapshot, range) =
 4143                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4144
 4145                                let num_of_whitespaces = snapshot
 4146                                    .chars_for_range(range.clone())
 4147                                    .take_while(|c| c.is_whitespace())
 4148                                    .count();
 4149                                let comment_candidate = snapshot
 4150                                    .chars_for_range(range)
 4151                                    .skip(num_of_whitespaces)
 4152                                    .take(max_len_of_delimiter)
 4153                                    .collect::<String>();
 4154                                let (delimiter, trimmed_len) = delimiters
 4155                                    .iter()
 4156                                    .filter_map(|delimiter| {
 4157                                        let prefix = delimiter.trim_end();
 4158                                        if comment_candidate.starts_with(prefix) {
 4159                                            Some((delimiter, prefix.len()))
 4160                                        } else {
 4161                                            None
 4162                                        }
 4163                                    })
 4164                                    .max_by_key(|(_, len)| *len)?;
 4165
 4166                                let cursor_is_placed_after_comment_marker =
 4167                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4168                                if cursor_is_placed_after_comment_marker {
 4169                                    Some(delimiter.clone())
 4170                                } else {
 4171                                    None
 4172                                }
 4173                            });
 4174
 4175                            let mut indent_on_newline = IndentSize::spaces(0);
 4176                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4177
 4178                            let doc_delimiter = maybe!({
 4179                                if !selection_is_empty {
 4180                                    return None;
 4181                                }
 4182
 4183                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4184                                    return None;
 4185                                }
 4186
 4187                                let DocumentationConfig {
 4188                                    start: start_tag,
 4189                                    end: end_tag,
 4190                                    prefix: delimiter,
 4191                                    tab_size: len,
 4192                                } = language.documentation()?;
 4193
 4194                                let is_within_block_comment = buffer
 4195                                    .language_scope_at(start_point)
 4196                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4197                                if !is_within_block_comment {
 4198                                    return None;
 4199                                }
 4200
 4201                                let (snapshot, range) =
 4202                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4203
 4204                                let num_of_whitespaces = snapshot
 4205                                    .chars_for_range(range.clone())
 4206                                    .take_while(|c| c.is_whitespace())
 4207                                    .count();
 4208
 4209                                // 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.
 4210                                let column = start_point.column;
 4211                                let cursor_is_after_start_tag = {
 4212                                    let start_tag_len = start_tag.len();
 4213                                    let start_tag_line = snapshot
 4214                                        .chars_for_range(range.clone())
 4215                                        .skip(num_of_whitespaces)
 4216                                        .take(start_tag_len)
 4217                                        .collect::<String>();
 4218                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4219                                        num_of_whitespaces + start_tag_len <= column as usize
 4220                                    } else {
 4221                                        false
 4222                                    }
 4223                                };
 4224
 4225                                let cursor_is_after_delimiter = {
 4226                                    let delimiter_trim = delimiter.trim_end();
 4227                                    let delimiter_line = snapshot
 4228                                        .chars_for_range(range.clone())
 4229                                        .skip(num_of_whitespaces)
 4230                                        .take(delimiter_trim.len())
 4231                                        .collect::<String>();
 4232                                    if delimiter_line.starts_with(delimiter_trim) {
 4233                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4234                                    } else {
 4235                                        false
 4236                                    }
 4237                                };
 4238
 4239                                let cursor_is_before_end_tag_if_exists = {
 4240                                    let mut char_position = 0u32;
 4241                                    let mut end_tag_offset = None;
 4242
 4243                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4244                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4245                                            let chars_before_match =
 4246                                                chunk[..byte_pos].chars().count() as u32;
 4247                                            end_tag_offset =
 4248                                                Some(char_position + chars_before_match);
 4249                                            break 'outer;
 4250                                        }
 4251                                        char_position += chunk.chars().count() as u32;
 4252                                    }
 4253
 4254                                    if let Some(end_tag_offset) = end_tag_offset {
 4255                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4256                                        if cursor_is_after_start_tag {
 4257                                            if cursor_is_before_end_tag {
 4258                                                insert_extra_newline = true;
 4259                                            }
 4260                                            let cursor_is_at_start_of_end_tag =
 4261                                                column == end_tag_offset;
 4262                                            if cursor_is_at_start_of_end_tag {
 4263                                                indent_on_extra_newline.len = (*len).into();
 4264                                            }
 4265                                        }
 4266                                        cursor_is_before_end_tag
 4267                                    } else {
 4268                                        true
 4269                                    }
 4270                                };
 4271
 4272                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4273                                    && cursor_is_before_end_tag_if_exists
 4274                                {
 4275                                    if cursor_is_after_start_tag {
 4276                                        indent_on_newline.len = (*len).into();
 4277                                    }
 4278                                    Some(delimiter.clone())
 4279                                } else {
 4280                                    None
 4281                                }
 4282                            });
 4283
 4284                            (
 4285                                comment_delimiter,
 4286                                doc_delimiter,
 4287                                insert_extra_newline,
 4288                                indent_on_newline,
 4289                                indent_on_extra_newline,
 4290                            )
 4291                        } else {
 4292                            (
 4293                                None,
 4294                                None,
 4295                                false,
 4296                                IndentSize::default(),
 4297                                IndentSize::default(),
 4298                            )
 4299                        };
 4300
 4301                        let prevent_auto_indent = doc_delimiter.is_some();
 4302                        let delimiter = comment_delimiter.or(doc_delimiter);
 4303
 4304                        let capacity_for_delimiter =
 4305                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4306                        let mut new_text = String::with_capacity(
 4307                            1 + capacity_for_delimiter
 4308                                + existing_indent.len as usize
 4309                                + indent_on_newline.len as usize
 4310                                + indent_on_extra_newline.len as usize,
 4311                        );
 4312                        new_text.push('\n');
 4313                        new_text.extend(existing_indent.chars());
 4314                        new_text.extend(indent_on_newline.chars());
 4315
 4316                        if let Some(delimiter) = &delimiter {
 4317                            new_text.push_str(delimiter);
 4318                        }
 4319
 4320                        if insert_extra_newline {
 4321                            new_text.push('\n');
 4322                            new_text.extend(existing_indent.chars());
 4323                            new_text.extend(indent_on_extra_newline.chars());
 4324                        }
 4325
 4326                        let anchor = buffer.anchor_after(end);
 4327                        let new_selection = selection.map(|_| anchor);
 4328                        (
 4329                            ((start..end, new_text), prevent_auto_indent),
 4330                            (insert_extra_newline, new_selection),
 4331                        )
 4332                    })
 4333                    .unzip()
 4334            };
 4335
 4336            let mut auto_indent_edits = Vec::new();
 4337            let mut edits = Vec::new();
 4338            for (edit, prevent_auto_indent) in edits_with_flags {
 4339                if prevent_auto_indent {
 4340                    edits.push(edit);
 4341                } else {
 4342                    auto_indent_edits.push(edit);
 4343                }
 4344            }
 4345            if !edits.is_empty() {
 4346                this.edit(edits, cx);
 4347            }
 4348            if !auto_indent_edits.is_empty() {
 4349                this.edit_with_autoindent(auto_indent_edits, cx);
 4350            }
 4351
 4352            let buffer = this.buffer.read(cx).snapshot(cx);
 4353            let new_selections = selection_info
 4354                .into_iter()
 4355                .map(|(extra_newline_inserted, new_selection)| {
 4356                    let mut cursor = new_selection.end.to_point(&buffer);
 4357                    if extra_newline_inserted {
 4358                        cursor.row -= 1;
 4359                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4360                    }
 4361                    new_selection.map(|_| cursor)
 4362                })
 4363                .collect();
 4364
 4365            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4366                s.select(new_selections)
 4367            });
 4368            this.refresh_inline_completion(true, false, window, cx);
 4369        });
 4370    }
 4371
 4372    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4373        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4374
 4375        let buffer = self.buffer.read(cx);
 4376        let snapshot = buffer.snapshot(cx);
 4377
 4378        let mut edits = Vec::new();
 4379        let mut rows = Vec::new();
 4380
 4381        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4382            let cursor = selection.head();
 4383            let row = cursor.row;
 4384
 4385            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4386
 4387            let newline = "\n".to_string();
 4388            edits.push((start_of_line..start_of_line, newline));
 4389
 4390            rows.push(row + rows_inserted as u32);
 4391        }
 4392
 4393        self.transact(window, cx, |editor, window, cx| {
 4394            editor.edit(edits, cx);
 4395
 4396            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4397                let mut index = 0;
 4398                s.move_cursors_with(|map, _, _| {
 4399                    let row = rows[index];
 4400                    index += 1;
 4401
 4402                    let point = Point::new(row, 0);
 4403                    let boundary = map.next_line_boundary(point).1;
 4404                    let clipped = map.clip_point(boundary, Bias::Left);
 4405
 4406                    (clipped, SelectionGoal::None)
 4407                });
 4408            });
 4409
 4410            let mut indent_edits = Vec::new();
 4411            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4412            for row in rows {
 4413                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4414                for (row, indent) in indents {
 4415                    if indent.len == 0 {
 4416                        continue;
 4417                    }
 4418
 4419                    let text = match indent.kind {
 4420                        IndentKind::Space => " ".repeat(indent.len as usize),
 4421                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4422                    };
 4423                    let point = Point::new(row.0, 0);
 4424                    indent_edits.push((point..point, text));
 4425                }
 4426            }
 4427            editor.edit(indent_edits, cx);
 4428        });
 4429    }
 4430
 4431    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4432        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4433
 4434        let buffer = self.buffer.read(cx);
 4435        let snapshot = buffer.snapshot(cx);
 4436
 4437        let mut edits = Vec::new();
 4438        let mut rows = Vec::new();
 4439        let mut rows_inserted = 0;
 4440
 4441        for selection in self.selections.all_adjusted(cx) {
 4442            let cursor = selection.head();
 4443            let row = cursor.row;
 4444
 4445            let point = Point::new(row + 1, 0);
 4446            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4447
 4448            let newline = "\n".to_string();
 4449            edits.push((start_of_line..start_of_line, newline));
 4450
 4451            rows_inserted += 1;
 4452            rows.push(row + rows_inserted);
 4453        }
 4454
 4455        self.transact(window, cx, |editor, window, cx| {
 4456            editor.edit(edits, cx);
 4457
 4458            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4459                let mut index = 0;
 4460                s.move_cursors_with(|map, _, _| {
 4461                    let row = rows[index];
 4462                    index += 1;
 4463
 4464                    let point = Point::new(row, 0);
 4465                    let boundary = map.next_line_boundary(point).1;
 4466                    let clipped = map.clip_point(boundary, Bias::Left);
 4467
 4468                    (clipped, SelectionGoal::None)
 4469                });
 4470            });
 4471
 4472            let mut indent_edits = Vec::new();
 4473            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4474            for row in rows {
 4475                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4476                for (row, indent) in indents {
 4477                    if indent.len == 0 {
 4478                        continue;
 4479                    }
 4480
 4481                    let text = match indent.kind {
 4482                        IndentKind::Space => " ".repeat(indent.len as usize),
 4483                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4484                    };
 4485                    let point = Point::new(row.0, 0);
 4486                    indent_edits.push((point..point, text));
 4487                }
 4488            }
 4489            editor.edit(indent_edits, cx);
 4490        });
 4491    }
 4492
 4493    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4494        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4495            original_indent_columns: Vec::new(),
 4496        });
 4497        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4498    }
 4499
 4500    fn insert_with_autoindent_mode(
 4501        &mut self,
 4502        text: &str,
 4503        autoindent_mode: Option<AutoindentMode>,
 4504        window: &mut Window,
 4505        cx: &mut Context<Self>,
 4506    ) {
 4507        if self.read_only(cx) {
 4508            return;
 4509        }
 4510
 4511        let text: Arc<str> = text.into();
 4512        self.transact(window, cx, |this, window, cx| {
 4513            let old_selections = this.selections.all_adjusted(cx);
 4514            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4515                let anchors = {
 4516                    let snapshot = buffer.read(cx);
 4517                    old_selections
 4518                        .iter()
 4519                        .map(|s| {
 4520                            let anchor = snapshot.anchor_after(s.head());
 4521                            s.map(|_| anchor)
 4522                        })
 4523                        .collect::<Vec<_>>()
 4524                };
 4525                buffer.edit(
 4526                    old_selections
 4527                        .iter()
 4528                        .map(|s| (s.start..s.end, text.clone())),
 4529                    autoindent_mode,
 4530                    cx,
 4531                );
 4532                anchors
 4533            });
 4534
 4535            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4536                s.select_anchors(selection_anchors);
 4537            });
 4538
 4539            cx.notify();
 4540        });
 4541    }
 4542
 4543    fn trigger_completion_on_input(
 4544        &mut self,
 4545        text: &str,
 4546        trigger_in_words: bool,
 4547        window: &mut Window,
 4548        cx: &mut Context<Self>,
 4549    ) {
 4550        let completions_source = self
 4551            .context_menu
 4552            .borrow()
 4553            .as_ref()
 4554            .and_then(|menu| match menu {
 4555                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4556                CodeContextMenu::CodeActions(_) => None,
 4557            });
 4558
 4559        match completions_source {
 4560            Some(CompletionsMenuSource::Words) => {
 4561                self.show_word_completions(&ShowWordCompletions, window, cx)
 4562            }
 4563            Some(CompletionsMenuSource::Normal)
 4564            | Some(CompletionsMenuSource::SnippetChoices)
 4565            | None
 4566                if self.is_completion_trigger(
 4567                    text,
 4568                    trigger_in_words,
 4569                    completions_source.is_some(),
 4570                    cx,
 4571                ) =>
 4572            {
 4573                self.show_completions(
 4574                    &ShowCompletions {
 4575                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4576                    },
 4577                    window,
 4578                    cx,
 4579                )
 4580            }
 4581            _ => {
 4582                self.hide_context_menu(window, cx);
 4583            }
 4584        }
 4585    }
 4586
 4587    fn is_completion_trigger(
 4588        &self,
 4589        text: &str,
 4590        trigger_in_words: bool,
 4591        menu_is_open: bool,
 4592        cx: &mut Context<Self>,
 4593    ) -> bool {
 4594        let position = self.selections.newest_anchor().head();
 4595        let multibuffer = self.buffer.read(cx);
 4596        let Some(buffer) = position
 4597            .buffer_id
 4598            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4599        else {
 4600            return false;
 4601        };
 4602
 4603        if let Some(completion_provider) = &self.completion_provider {
 4604            completion_provider.is_completion_trigger(
 4605                &buffer,
 4606                position.text_anchor,
 4607                text,
 4608                trigger_in_words,
 4609                menu_is_open,
 4610                cx,
 4611            )
 4612        } else {
 4613            false
 4614        }
 4615    }
 4616
 4617    /// If any empty selections is touching the start of its innermost containing autoclose
 4618    /// region, expand it to select the brackets.
 4619    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4620        let selections = self.selections.all::<usize>(cx);
 4621        let buffer = self.buffer.read(cx).read(cx);
 4622        let new_selections = self
 4623            .selections_with_autoclose_regions(selections, &buffer)
 4624            .map(|(mut selection, region)| {
 4625                if !selection.is_empty() {
 4626                    return selection;
 4627                }
 4628
 4629                if let Some(region) = region {
 4630                    let mut range = region.range.to_offset(&buffer);
 4631                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4632                        range.start -= region.pair.start.len();
 4633                        if buffer.contains_str_at(range.start, &region.pair.start)
 4634                            && buffer.contains_str_at(range.end, &region.pair.end)
 4635                        {
 4636                            range.end += region.pair.end.len();
 4637                            selection.start = range.start;
 4638                            selection.end = range.end;
 4639
 4640                            return selection;
 4641                        }
 4642                    }
 4643                }
 4644
 4645                let always_treat_brackets_as_autoclosed = buffer
 4646                    .language_settings_at(selection.start, cx)
 4647                    .always_treat_brackets_as_autoclosed;
 4648
 4649                if !always_treat_brackets_as_autoclosed {
 4650                    return selection;
 4651                }
 4652
 4653                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4654                    for (pair, enabled) in scope.brackets() {
 4655                        if !enabled || !pair.close {
 4656                            continue;
 4657                        }
 4658
 4659                        if buffer.contains_str_at(selection.start, &pair.end) {
 4660                            let pair_start_len = pair.start.len();
 4661                            if buffer.contains_str_at(
 4662                                selection.start.saturating_sub(pair_start_len),
 4663                                &pair.start,
 4664                            ) {
 4665                                selection.start -= pair_start_len;
 4666                                selection.end += pair.end.len();
 4667
 4668                                return selection;
 4669                            }
 4670                        }
 4671                    }
 4672                }
 4673
 4674                selection
 4675            })
 4676            .collect();
 4677
 4678        drop(buffer);
 4679        self.change_selections(None, window, cx, |selections| {
 4680            selections.select(new_selections)
 4681        });
 4682    }
 4683
 4684    /// Iterate the given selections, and for each one, find the smallest surrounding
 4685    /// autoclose region. This uses the ordering of the selections and the autoclose
 4686    /// regions to avoid repeated comparisons.
 4687    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4688        &'a self,
 4689        selections: impl IntoIterator<Item = Selection<D>>,
 4690        buffer: &'a MultiBufferSnapshot,
 4691    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4692        let mut i = 0;
 4693        let mut regions = self.autoclose_regions.as_slice();
 4694        selections.into_iter().map(move |selection| {
 4695            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4696
 4697            let mut enclosing = None;
 4698            while let Some(pair_state) = regions.get(i) {
 4699                if pair_state.range.end.to_offset(buffer) < range.start {
 4700                    regions = &regions[i + 1..];
 4701                    i = 0;
 4702                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4703                    break;
 4704                } else {
 4705                    if pair_state.selection_id == selection.id {
 4706                        enclosing = Some(pair_state);
 4707                    }
 4708                    i += 1;
 4709                }
 4710            }
 4711
 4712            (selection, enclosing)
 4713        })
 4714    }
 4715
 4716    /// Remove any autoclose regions that no longer contain their selection.
 4717    fn invalidate_autoclose_regions(
 4718        &mut self,
 4719        mut selections: &[Selection<Anchor>],
 4720        buffer: &MultiBufferSnapshot,
 4721    ) {
 4722        self.autoclose_regions.retain(|state| {
 4723            let mut i = 0;
 4724            while let Some(selection) = selections.get(i) {
 4725                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4726                    selections = &selections[1..];
 4727                    continue;
 4728                }
 4729                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4730                    break;
 4731                }
 4732                if selection.id == state.selection_id {
 4733                    return true;
 4734                } else {
 4735                    i += 1;
 4736                }
 4737            }
 4738            false
 4739        });
 4740    }
 4741
 4742    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4743        let offset = position.to_offset(buffer);
 4744        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4745        if offset > word_range.start && kind == Some(CharKind::Word) {
 4746            Some(
 4747                buffer
 4748                    .text_for_range(word_range.start..offset)
 4749                    .collect::<String>(),
 4750            )
 4751        } else {
 4752            None
 4753        }
 4754    }
 4755
 4756    pub fn toggle_inline_values(
 4757        &mut self,
 4758        _: &ToggleInlineValues,
 4759        _: &mut Window,
 4760        cx: &mut Context<Self>,
 4761    ) {
 4762        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4763
 4764        self.refresh_inline_values(cx);
 4765    }
 4766
 4767    pub fn toggle_inlay_hints(
 4768        &mut self,
 4769        _: &ToggleInlayHints,
 4770        _: &mut Window,
 4771        cx: &mut Context<Self>,
 4772    ) {
 4773        self.refresh_inlay_hints(
 4774            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4775            cx,
 4776        );
 4777    }
 4778
 4779    pub fn inlay_hints_enabled(&self) -> bool {
 4780        self.inlay_hint_cache.enabled
 4781    }
 4782
 4783    pub fn inline_values_enabled(&self) -> bool {
 4784        self.inline_value_cache.enabled
 4785    }
 4786
 4787    #[cfg(any(test, feature = "test-support"))]
 4788    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4789        self.display_map
 4790            .read(cx)
 4791            .current_inlays()
 4792            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4793            .cloned()
 4794            .collect()
 4795    }
 4796
 4797    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4798        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4799            return;
 4800        }
 4801
 4802        let reason_description = reason.description();
 4803        let ignore_debounce = matches!(
 4804            reason,
 4805            InlayHintRefreshReason::SettingsChange(_)
 4806                | InlayHintRefreshReason::Toggle(_)
 4807                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4808                | InlayHintRefreshReason::ModifiersChanged(_)
 4809        );
 4810        let (invalidate_cache, required_languages) = match reason {
 4811            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4812                match self.inlay_hint_cache.modifiers_override(enabled) {
 4813                    Some(enabled) => {
 4814                        if enabled {
 4815                            (InvalidationStrategy::RefreshRequested, None)
 4816                        } else {
 4817                            self.splice_inlays(
 4818                                &self
 4819                                    .visible_inlay_hints(cx)
 4820                                    .iter()
 4821                                    .map(|inlay| inlay.id)
 4822                                    .collect::<Vec<InlayId>>(),
 4823                                Vec::new(),
 4824                                cx,
 4825                            );
 4826                            return;
 4827                        }
 4828                    }
 4829                    None => return,
 4830                }
 4831            }
 4832            InlayHintRefreshReason::Toggle(enabled) => {
 4833                if self.inlay_hint_cache.toggle(enabled) {
 4834                    if enabled {
 4835                        (InvalidationStrategy::RefreshRequested, None)
 4836                    } else {
 4837                        self.splice_inlays(
 4838                            &self
 4839                                .visible_inlay_hints(cx)
 4840                                .iter()
 4841                                .map(|inlay| inlay.id)
 4842                                .collect::<Vec<InlayId>>(),
 4843                            Vec::new(),
 4844                            cx,
 4845                        );
 4846                        return;
 4847                    }
 4848                } else {
 4849                    return;
 4850                }
 4851            }
 4852            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4853                match self.inlay_hint_cache.update_settings(
 4854                    &self.buffer,
 4855                    new_settings,
 4856                    self.visible_inlay_hints(cx),
 4857                    cx,
 4858                ) {
 4859                    ControlFlow::Break(Some(InlaySplice {
 4860                        to_remove,
 4861                        to_insert,
 4862                    })) => {
 4863                        self.splice_inlays(&to_remove, to_insert, cx);
 4864                        return;
 4865                    }
 4866                    ControlFlow::Break(None) => return,
 4867                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4868                }
 4869            }
 4870            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4871                if let Some(InlaySplice {
 4872                    to_remove,
 4873                    to_insert,
 4874                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4875                {
 4876                    self.splice_inlays(&to_remove, to_insert, cx);
 4877                }
 4878                self.display_map.update(cx, |display_map, _| {
 4879                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4880                });
 4881                return;
 4882            }
 4883            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4884            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4885                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4886            }
 4887            InlayHintRefreshReason::RefreshRequested => {
 4888                (InvalidationStrategy::RefreshRequested, None)
 4889            }
 4890        };
 4891
 4892        if let Some(InlaySplice {
 4893            to_remove,
 4894            to_insert,
 4895        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4896            reason_description,
 4897            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4898            invalidate_cache,
 4899            ignore_debounce,
 4900            cx,
 4901        ) {
 4902            self.splice_inlays(&to_remove, to_insert, cx);
 4903        }
 4904    }
 4905
 4906    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4907        self.display_map
 4908            .read(cx)
 4909            .current_inlays()
 4910            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4911            .cloned()
 4912            .collect()
 4913    }
 4914
 4915    pub fn excerpts_for_inlay_hints_query(
 4916        &self,
 4917        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4918        cx: &mut Context<Editor>,
 4919    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4920        let Some(project) = self.project.as_ref() else {
 4921            return HashMap::default();
 4922        };
 4923        let project = project.read(cx);
 4924        let multi_buffer = self.buffer().read(cx);
 4925        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4926        let multi_buffer_visible_start = self
 4927            .scroll_manager
 4928            .anchor()
 4929            .anchor
 4930            .to_point(&multi_buffer_snapshot);
 4931        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4932            multi_buffer_visible_start
 4933                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4934            Bias::Left,
 4935        );
 4936        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4937        multi_buffer_snapshot
 4938            .range_to_buffer_ranges(multi_buffer_visible_range)
 4939            .into_iter()
 4940            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4941            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4942                let buffer_file = project::File::from_dyn(buffer.file())?;
 4943                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4944                let worktree_entry = buffer_worktree
 4945                    .read(cx)
 4946                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4947                if worktree_entry.is_ignored {
 4948                    return None;
 4949                }
 4950
 4951                let language = buffer.language()?;
 4952                if let Some(restrict_to_languages) = restrict_to_languages {
 4953                    if !restrict_to_languages.contains(language) {
 4954                        return None;
 4955                    }
 4956                }
 4957                Some((
 4958                    excerpt_id,
 4959                    (
 4960                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4961                        buffer.version().clone(),
 4962                        excerpt_visible_range,
 4963                    ),
 4964                ))
 4965            })
 4966            .collect()
 4967    }
 4968
 4969    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4970        TextLayoutDetails {
 4971            text_system: window.text_system().clone(),
 4972            editor_style: self.style.clone().unwrap(),
 4973            rem_size: window.rem_size(),
 4974            scroll_anchor: self.scroll_manager.anchor(),
 4975            visible_rows: self.visible_line_count(),
 4976            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4977        }
 4978    }
 4979
 4980    pub fn splice_inlays(
 4981        &self,
 4982        to_remove: &[InlayId],
 4983        to_insert: Vec<Inlay>,
 4984        cx: &mut Context<Self>,
 4985    ) {
 4986        self.display_map.update(cx, |display_map, cx| {
 4987            display_map.splice_inlays(to_remove, to_insert, cx)
 4988        });
 4989        cx.notify();
 4990    }
 4991
 4992    fn trigger_on_type_formatting(
 4993        &self,
 4994        input: String,
 4995        window: &mut Window,
 4996        cx: &mut Context<Self>,
 4997    ) -> Option<Task<Result<()>>> {
 4998        if input.len() != 1 {
 4999            return None;
 5000        }
 5001
 5002        let project = self.project.as_ref()?;
 5003        let position = self.selections.newest_anchor().head();
 5004        let (buffer, buffer_position) = self
 5005            .buffer
 5006            .read(cx)
 5007            .text_anchor_for_position(position, cx)?;
 5008
 5009        let settings = language_settings::language_settings(
 5010            buffer
 5011                .read(cx)
 5012                .language_at(buffer_position)
 5013                .map(|l| l.name()),
 5014            buffer.read(cx).file(),
 5015            cx,
 5016        );
 5017        if !settings.use_on_type_format {
 5018            return None;
 5019        }
 5020
 5021        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5022        // hence we do LSP request & edit on host side only — add formats to host's history.
 5023        let push_to_lsp_host_history = true;
 5024        // If this is not the host, append its history with new edits.
 5025        let push_to_client_history = project.read(cx).is_via_collab();
 5026
 5027        let on_type_formatting = project.update(cx, |project, cx| {
 5028            project.on_type_format(
 5029                buffer.clone(),
 5030                buffer_position,
 5031                input,
 5032                push_to_lsp_host_history,
 5033                cx,
 5034            )
 5035        });
 5036        Some(cx.spawn_in(window, async move |editor, cx| {
 5037            if let Some(transaction) = on_type_formatting.await? {
 5038                if push_to_client_history {
 5039                    buffer
 5040                        .update(cx, |buffer, _| {
 5041                            buffer.push_transaction(transaction, Instant::now());
 5042                            buffer.finalize_last_transaction();
 5043                        })
 5044                        .ok();
 5045                }
 5046                editor.update(cx, |editor, cx| {
 5047                    editor.refresh_document_highlights(cx);
 5048                })?;
 5049            }
 5050            Ok(())
 5051        }))
 5052    }
 5053
 5054    pub fn show_word_completions(
 5055        &mut self,
 5056        _: &ShowWordCompletions,
 5057        window: &mut Window,
 5058        cx: &mut Context<Self>,
 5059    ) {
 5060        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5061    }
 5062
 5063    pub fn show_completions(
 5064        &mut self,
 5065        options: &ShowCompletions,
 5066        window: &mut Window,
 5067        cx: &mut Context<Self>,
 5068    ) {
 5069        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5070    }
 5071
 5072    fn open_or_update_completions_menu(
 5073        &mut self,
 5074        requested_source: Option<CompletionsMenuSource>,
 5075        trigger: Option<&str>,
 5076        window: &mut Window,
 5077        cx: &mut Context<Self>,
 5078    ) {
 5079        if self.pending_rename.is_some() {
 5080            return;
 5081        }
 5082
 5083        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5084
 5085        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5086        // inserted and selected. To handle that case, the start of the selection is used so that
 5087        // the menu starts with all choices.
 5088        let position = self
 5089            .selections
 5090            .newest_anchor()
 5091            .start
 5092            .bias_right(&multibuffer_snapshot);
 5093        if position.diff_base_anchor.is_some() {
 5094            return;
 5095        }
 5096        let (buffer, buffer_position) =
 5097            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5098                output
 5099            } else {
 5100                return;
 5101            };
 5102        let buffer_snapshot = buffer.read(cx).snapshot();
 5103
 5104        let query: Option<Arc<String>> =
 5105            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5106
 5107        drop(multibuffer_snapshot);
 5108
 5109        let provider = match requested_source {
 5110            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5111            Some(CompletionsMenuSource::Words) => None,
 5112            Some(CompletionsMenuSource::SnippetChoices) => {
 5113                log::error!("bug: SnippetChoices requested_source is not handled");
 5114                None
 5115            }
 5116        };
 5117
 5118        let sort_completions = provider
 5119            .as_ref()
 5120            .map_or(false, |provider| provider.sort_completions());
 5121
 5122        let filter_completions = provider
 5123            .as_ref()
 5124            .map_or(true, |provider| provider.filter_completions());
 5125
 5126        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5127        // current query is a suffix of the initial query.
 5128        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5129            if !menu.is_incomplete && filter_completions {
 5130                // If the new query is a suffix of the old query (typing more characters) and
 5131                // the previous result was complete, the existing completions can be filtered.
 5132                //
 5133                // Note that this is always true for snippet completions.
 5134                let query_matches = match (&menu.initial_query, &query) {
 5135                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5136                    (None, _) => true,
 5137                    _ => false,
 5138                };
 5139                if query_matches {
 5140                    let position_matches = if menu.initial_position == position {
 5141                        true
 5142                    } else {
 5143                        let snapshot = self.buffer.read(cx).read(cx);
 5144                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5145                    };
 5146                    if position_matches {
 5147                        menu.filter(query.clone(), provider.clone(), window, cx);
 5148                        return;
 5149                    }
 5150                }
 5151            }
 5152        };
 5153
 5154        let trigger_kind = match trigger {
 5155            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5156                CompletionTriggerKind::TRIGGER_CHARACTER
 5157            }
 5158            _ => CompletionTriggerKind::INVOKED,
 5159        };
 5160        let completion_context = CompletionContext {
 5161            trigger_character: trigger.and_then(|trigger| {
 5162                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5163                    Some(String::from(trigger))
 5164                } else {
 5165                    None
 5166                }
 5167            }),
 5168            trigger_kind,
 5169        };
 5170
 5171        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5172            buffer_snapshot.surrounding_word(buffer_position)
 5173        {
 5174            let word_to_exclude = buffer_snapshot
 5175                .text_for_range(word_range.clone())
 5176                .collect::<String>();
 5177            (
 5178                buffer_snapshot.anchor_before(word_range.start)
 5179                    ..buffer_snapshot.anchor_after(buffer_position),
 5180                Some(word_to_exclude),
 5181            )
 5182        } else {
 5183            (buffer_position..buffer_position, None)
 5184        };
 5185
 5186        let language = buffer_snapshot
 5187            .language_at(buffer_position)
 5188            .map(|language| language.name());
 5189
 5190        let completion_settings =
 5191            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5192
 5193        let show_completion_documentation = buffer_snapshot
 5194            .settings_at(buffer_position, cx)
 5195            .show_completion_documentation;
 5196
 5197        // The document can be large, so stay in reasonable bounds when searching for words,
 5198        // otherwise completion pop-up might be slow to appear.
 5199        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5200        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5201        let min_word_search = buffer_snapshot.clip_point(
 5202            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5203            Bias::Left,
 5204        );
 5205        let max_word_search = buffer_snapshot.clip_point(
 5206            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5207            Bias::Right,
 5208        );
 5209        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5210            ..buffer_snapshot.point_to_offset(max_word_search);
 5211
 5212        let skip_digits = query
 5213            .as_ref()
 5214            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5215
 5216        let (mut words, provider_responses) = match &provider {
 5217            Some(provider) => {
 5218                let provider_responses = provider.completions(
 5219                    position.excerpt_id,
 5220                    &buffer,
 5221                    buffer_position,
 5222                    completion_context,
 5223                    window,
 5224                    cx,
 5225                );
 5226
 5227                let words = match completion_settings.words {
 5228                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5229                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5230                        .background_spawn(async move {
 5231                            buffer_snapshot.words_in_range(WordsQuery {
 5232                                fuzzy_contents: None,
 5233                                range: word_search_range,
 5234                                skip_digits,
 5235                            })
 5236                        }),
 5237                };
 5238
 5239                (words, provider_responses)
 5240            }
 5241            None => (
 5242                cx.background_spawn(async move {
 5243                    buffer_snapshot.words_in_range(WordsQuery {
 5244                        fuzzy_contents: None,
 5245                        range: word_search_range,
 5246                        skip_digits,
 5247                    })
 5248                }),
 5249                Task::ready(Ok(Vec::new())),
 5250            ),
 5251        };
 5252
 5253        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5254
 5255        let id = post_inc(&mut self.next_completion_id);
 5256        let task = cx.spawn_in(window, async move |editor, cx| {
 5257            let Ok(()) = editor.update(cx, |this, _| {
 5258                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5259            }) else {
 5260                return;
 5261            };
 5262
 5263            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5264            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5265            let mut completions = Vec::new();
 5266            let mut is_incomplete = false;
 5267            if let Some(provider_responses) = provider_responses.await.log_err() {
 5268                if !provider_responses.is_empty() {
 5269                    for response in provider_responses {
 5270                        completions.extend(response.completions);
 5271                        is_incomplete = is_incomplete || response.is_incomplete;
 5272                    }
 5273                    if completion_settings.words == WordsCompletionMode::Fallback {
 5274                        words = Task::ready(BTreeMap::default());
 5275                    }
 5276                }
 5277            }
 5278
 5279            let mut words = words.await;
 5280            if let Some(word_to_exclude) = &word_to_exclude {
 5281                words.remove(word_to_exclude);
 5282            }
 5283            for lsp_completion in &completions {
 5284                words.remove(&lsp_completion.new_text);
 5285            }
 5286            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5287                replace_range: word_replace_range.clone(),
 5288                new_text: word.clone(),
 5289                label: CodeLabel::plain(word, None),
 5290                icon_path: None,
 5291                documentation: None,
 5292                source: CompletionSource::BufferWord {
 5293                    word_range,
 5294                    resolved: false,
 5295                },
 5296                insert_text_mode: Some(InsertTextMode::AS_IS),
 5297                confirm: None,
 5298            }));
 5299
 5300            let menu = if completions.is_empty() {
 5301                None
 5302            } else {
 5303                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5304                    let languages = editor
 5305                        .workspace
 5306                        .as_ref()
 5307                        .and_then(|(workspace, _)| workspace.upgrade())
 5308                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5309                    let menu = CompletionsMenu::new(
 5310                        id,
 5311                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5312                        sort_completions,
 5313                        show_completion_documentation,
 5314                        position,
 5315                        query.clone(),
 5316                        is_incomplete,
 5317                        buffer.clone(),
 5318                        completions.into(),
 5319                        snippet_sort_order,
 5320                        languages,
 5321                        language,
 5322                        cx,
 5323                    );
 5324
 5325                    let query = if filter_completions { query } else { None };
 5326                    let matches_task = if let Some(query) = query {
 5327                        menu.do_async_filtering(query, cx)
 5328                    } else {
 5329                        Task::ready(menu.unfiltered_matches())
 5330                    };
 5331                    (menu, matches_task)
 5332                }) else {
 5333                    return;
 5334                };
 5335
 5336                let matches = matches_task.await;
 5337
 5338                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5339                    // Newer menu already set, so exit.
 5340                    match editor.context_menu.borrow().as_ref() {
 5341                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5342                            if prev_menu.id > id {
 5343                                return;
 5344                            }
 5345                        }
 5346                        _ => {}
 5347                    };
 5348
 5349                    // Only valid to take prev_menu because it the new menu is immediately set
 5350                    // below, or the menu is hidden.
 5351                    match editor.context_menu.borrow_mut().take() {
 5352                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5353                            let position_matches =
 5354                                if prev_menu.initial_position == menu.initial_position {
 5355                                    true
 5356                                } else {
 5357                                    let snapshot = editor.buffer.read(cx).read(cx);
 5358                                    prev_menu.initial_position.to_offset(&snapshot)
 5359                                        == menu.initial_position.to_offset(&snapshot)
 5360                                };
 5361                            if position_matches {
 5362                                // Preserve markdown cache before `set_filter_results` because it will
 5363                                // try to populate the documentation cache.
 5364                                menu.preserve_markdown_cache(prev_menu);
 5365                            }
 5366                        }
 5367                        _ => {}
 5368                    };
 5369
 5370                    menu.set_filter_results(matches, provider, window, cx);
 5371                }) else {
 5372                    return;
 5373                };
 5374
 5375                menu.visible().then_some(menu)
 5376            };
 5377
 5378            editor
 5379                .update_in(cx, |editor, window, cx| {
 5380                    if editor.focus_handle.is_focused(window) {
 5381                        if let Some(menu) = menu {
 5382                            *editor.context_menu.borrow_mut() =
 5383                                Some(CodeContextMenu::Completions(menu));
 5384
 5385                            crate::hover_popover::hide_hover(editor, cx);
 5386                            if editor.show_edit_predictions_in_menu() {
 5387                                editor.update_visible_inline_completion(window, cx);
 5388                            } else {
 5389                                editor.discard_inline_completion(false, cx);
 5390                            }
 5391
 5392                            cx.notify();
 5393                            return;
 5394                        }
 5395                    }
 5396
 5397                    if editor.completion_tasks.len() <= 1 {
 5398                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5399                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5400                        // If it was already hidden and we don't show inline completions in the menu, we should
 5401                        // also show the inline-completion when available.
 5402                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5403                            editor.update_visible_inline_completion(window, cx);
 5404                        }
 5405                    }
 5406                })
 5407                .ok();
 5408        });
 5409
 5410        self.completion_tasks.push((id, task));
 5411    }
 5412
 5413    #[cfg(feature = "test-support")]
 5414    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5415        let menu = self.context_menu.borrow();
 5416        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5417            let completions = menu.completions.borrow();
 5418            Some(completions.to_vec())
 5419        } else {
 5420            None
 5421        }
 5422    }
 5423
 5424    pub fn with_completions_menu_matching_id<R>(
 5425        &self,
 5426        id: CompletionId,
 5427        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5428    ) -> R {
 5429        let mut context_menu = self.context_menu.borrow_mut();
 5430        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5431            return f(None);
 5432        };
 5433        if completions_menu.id != id {
 5434            return f(None);
 5435        }
 5436        f(Some(completions_menu))
 5437    }
 5438
 5439    pub fn confirm_completion(
 5440        &mut self,
 5441        action: &ConfirmCompletion,
 5442        window: &mut Window,
 5443        cx: &mut Context<Self>,
 5444    ) -> Option<Task<Result<()>>> {
 5445        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5446        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5447    }
 5448
 5449    pub fn confirm_completion_insert(
 5450        &mut self,
 5451        _: &ConfirmCompletionInsert,
 5452        window: &mut Window,
 5453        cx: &mut Context<Self>,
 5454    ) -> Option<Task<Result<()>>> {
 5455        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5456        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5457    }
 5458
 5459    pub fn confirm_completion_replace(
 5460        &mut self,
 5461        _: &ConfirmCompletionReplace,
 5462        window: &mut Window,
 5463        cx: &mut Context<Self>,
 5464    ) -> Option<Task<Result<()>>> {
 5465        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5466        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5467    }
 5468
 5469    pub fn compose_completion(
 5470        &mut self,
 5471        action: &ComposeCompletion,
 5472        window: &mut Window,
 5473        cx: &mut Context<Self>,
 5474    ) -> Option<Task<Result<()>>> {
 5475        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5476        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5477    }
 5478
 5479    fn do_completion(
 5480        &mut self,
 5481        item_ix: Option<usize>,
 5482        intent: CompletionIntent,
 5483        window: &mut Window,
 5484        cx: &mut Context<Editor>,
 5485    ) -> Option<Task<Result<()>>> {
 5486        use language::ToOffset as _;
 5487
 5488        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5489        else {
 5490            return None;
 5491        };
 5492
 5493        let candidate_id = {
 5494            let entries = completions_menu.entries.borrow();
 5495            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5496            if self.show_edit_predictions_in_menu() {
 5497                self.discard_inline_completion(true, cx);
 5498            }
 5499            mat.candidate_id
 5500        };
 5501
 5502        let completion = completions_menu
 5503            .completions
 5504            .borrow()
 5505            .get(candidate_id)?
 5506            .clone();
 5507        cx.stop_propagation();
 5508
 5509        let buffer_handle = completions_menu.buffer.clone();
 5510
 5511        let CompletionEdit {
 5512            new_text,
 5513            snippet,
 5514            replace_range,
 5515        } = process_completion_for_edit(
 5516            &completion,
 5517            intent,
 5518            &buffer_handle,
 5519            &completions_menu.initial_position.text_anchor,
 5520            cx,
 5521        );
 5522
 5523        let buffer = buffer_handle.read(cx);
 5524        let snapshot = self.buffer.read(cx).snapshot(cx);
 5525        let newest_anchor = self.selections.newest_anchor();
 5526        let replace_range_multibuffer = {
 5527            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5528            let multibuffer_anchor = snapshot
 5529                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5530                .unwrap()
 5531                ..snapshot
 5532                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5533                    .unwrap();
 5534            multibuffer_anchor.start.to_offset(&snapshot)
 5535                ..multibuffer_anchor.end.to_offset(&snapshot)
 5536        };
 5537        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5538            return None;
 5539        }
 5540
 5541        let old_text = buffer
 5542            .text_for_range(replace_range.clone())
 5543            .collect::<String>();
 5544        let lookbehind = newest_anchor
 5545            .start
 5546            .text_anchor
 5547            .to_offset(buffer)
 5548            .saturating_sub(replace_range.start);
 5549        let lookahead = replace_range
 5550            .end
 5551            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5552        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5553        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5554
 5555        let selections = self.selections.all::<usize>(cx);
 5556        let mut ranges = Vec::new();
 5557        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5558
 5559        for selection in &selections {
 5560            let range = if selection.id == newest_anchor.id {
 5561                replace_range_multibuffer.clone()
 5562            } else {
 5563                let mut range = selection.range();
 5564
 5565                // if prefix is present, don't duplicate it
 5566                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5567                    range.start = range.start.saturating_sub(lookbehind);
 5568
 5569                    // if suffix is also present, mimic the newest cursor and replace it
 5570                    if selection.id != newest_anchor.id
 5571                        && snapshot.contains_str_at(range.end, suffix)
 5572                    {
 5573                        range.end += lookahead;
 5574                    }
 5575                }
 5576                range
 5577            };
 5578
 5579            ranges.push(range.clone());
 5580
 5581            if !self.linked_edit_ranges.is_empty() {
 5582                let start_anchor = snapshot.anchor_before(range.start);
 5583                let end_anchor = snapshot.anchor_after(range.end);
 5584                if let Some(ranges) = self
 5585                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5586                {
 5587                    for (buffer, edits) in ranges {
 5588                        linked_edits
 5589                            .entry(buffer.clone())
 5590                            .or_default()
 5591                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5592                    }
 5593                }
 5594            }
 5595        }
 5596
 5597        let common_prefix_len = old_text
 5598            .chars()
 5599            .zip(new_text.chars())
 5600            .take_while(|(a, b)| a == b)
 5601            .map(|(a, _)| a.len_utf8())
 5602            .sum::<usize>();
 5603
 5604        cx.emit(EditorEvent::InputHandled {
 5605            utf16_range_to_replace: None,
 5606            text: new_text[common_prefix_len..].into(),
 5607        });
 5608
 5609        self.transact(window, cx, |this, window, cx| {
 5610            if let Some(mut snippet) = snippet {
 5611                snippet.text = new_text.to_string();
 5612                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5613            } else {
 5614                this.buffer.update(cx, |buffer, cx| {
 5615                    let auto_indent = match completion.insert_text_mode {
 5616                        Some(InsertTextMode::AS_IS) => None,
 5617                        _ => this.autoindent_mode.clone(),
 5618                    };
 5619                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5620                    buffer.edit(edits, auto_indent, cx);
 5621                });
 5622            }
 5623            for (buffer, edits) in linked_edits {
 5624                buffer.update(cx, |buffer, cx| {
 5625                    let snapshot = buffer.snapshot();
 5626                    let edits = edits
 5627                        .into_iter()
 5628                        .map(|(range, text)| {
 5629                            use text::ToPoint as TP;
 5630                            let end_point = TP::to_point(&range.end, &snapshot);
 5631                            let start_point = TP::to_point(&range.start, &snapshot);
 5632                            (start_point..end_point, text)
 5633                        })
 5634                        .sorted_by_key(|(range, _)| range.start);
 5635                    buffer.edit(edits, None, cx);
 5636                })
 5637            }
 5638
 5639            this.refresh_inline_completion(true, false, window, cx);
 5640        });
 5641
 5642        let show_new_completions_on_confirm = completion
 5643            .confirm
 5644            .as_ref()
 5645            .map_or(false, |confirm| confirm(intent, window, cx));
 5646        if show_new_completions_on_confirm {
 5647            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5648        }
 5649
 5650        let provider = self.completion_provider.as_ref()?;
 5651        drop(completion);
 5652        let apply_edits = provider.apply_additional_edits_for_completion(
 5653            buffer_handle,
 5654            completions_menu.completions.clone(),
 5655            candidate_id,
 5656            true,
 5657            cx,
 5658        );
 5659
 5660        let editor_settings = EditorSettings::get_global(cx);
 5661        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5662            // After the code completion is finished, users often want to know what signatures are needed.
 5663            // so we should automatically call signature_help
 5664            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5665        }
 5666
 5667        Some(cx.foreground_executor().spawn(async move {
 5668            apply_edits.await?;
 5669            Ok(())
 5670        }))
 5671    }
 5672
 5673    pub fn toggle_code_actions(
 5674        &mut self,
 5675        action: &ToggleCodeActions,
 5676        window: &mut Window,
 5677        cx: &mut Context<Self>,
 5678    ) {
 5679        let quick_launch = action.quick_launch;
 5680        let mut context_menu = self.context_menu.borrow_mut();
 5681        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5682            if code_actions.deployed_from == action.deployed_from {
 5683                // Toggle if we're selecting the same one
 5684                *context_menu = None;
 5685                cx.notify();
 5686                return;
 5687            } else {
 5688                // Otherwise, clear it and start a new one
 5689                *context_menu = None;
 5690                cx.notify();
 5691            }
 5692        }
 5693        drop(context_menu);
 5694        let snapshot = self.snapshot(window, cx);
 5695        let deployed_from = action.deployed_from.clone();
 5696        let mut task = self.code_actions_task.take();
 5697        let action = action.clone();
 5698        cx.spawn_in(window, async move |editor, cx| {
 5699            while let Some(prev_task) = task {
 5700                prev_task.await.log_err();
 5701                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5702            }
 5703
 5704            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5705                if editor.focus_handle.is_focused(window) {
 5706                    let multibuffer_point = match &action.deployed_from {
 5707                        Some(CodeActionSource::Indicator(row)) => {
 5708                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5709                        }
 5710                        _ => editor.selections.newest::<Point>(cx).head(),
 5711                    };
 5712                    let (buffer, buffer_row) = snapshot
 5713                        .buffer_snapshot
 5714                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5715                        .and_then(|(buffer_snapshot, range)| {
 5716                            editor
 5717                                .buffer
 5718                                .read(cx)
 5719                                .buffer(buffer_snapshot.remote_id())
 5720                                .map(|buffer| (buffer, range.start.row))
 5721                        })?;
 5722                    let (_, code_actions) = editor
 5723                        .available_code_actions
 5724                        .clone()
 5725                        .and_then(|(location, code_actions)| {
 5726                            let snapshot = location.buffer.read(cx).snapshot();
 5727                            let point_range = location.range.to_point(&snapshot);
 5728                            let point_range = point_range.start.row..=point_range.end.row;
 5729                            if point_range.contains(&buffer_row) {
 5730                                Some((location, code_actions))
 5731                            } else {
 5732                                None
 5733                            }
 5734                        })
 5735                        .unzip();
 5736                    let buffer_id = buffer.read(cx).remote_id();
 5737                    let tasks = editor
 5738                        .tasks
 5739                        .get(&(buffer_id, buffer_row))
 5740                        .map(|t| Arc::new(t.to_owned()));
 5741                    if tasks.is_none() && code_actions.is_none() {
 5742                        return None;
 5743                    }
 5744
 5745                    editor.completion_tasks.clear();
 5746                    editor.discard_inline_completion(false, cx);
 5747                    let task_context =
 5748                        tasks
 5749                            .as_ref()
 5750                            .zip(editor.project.clone())
 5751                            .map(|(tasks, project)| {
 5752                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5753                            });
 5754
 5755                    Some(cx.spawn_in(window, async move |editor, cx| {
 5756                        let task_context = match task_context {
 5757                            Some(task_context) => task_context.await,
 5758                            None => None,
 5759                        };
 5760                        let resolved_tasks =
 5761                            tasks
 5762                                .zip(task_context.clone())
 5763                                .map(|(tasks, task_context)| ResolvedTasks {
 5764                                    templates: tasks.resolve(&task_context).collect(),
 5765                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5766                                        multibuffer_point.row,
 5767                                        tasks.column,
 5768                                    )),
 5769                                });
 5770                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5771                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5772                                maybe!({
 5773                                    let project = editor.project.as_ref()?;
 5774                                    let dap_store = project.read(cx).dap_store();
 5775                                    let mut scenarios = vec![];
 5776                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5777                                    let buffer = buffer.read(cx);
 5778                                    let language = buffer.language()?;
 5779                                    let file = buffer.file();
 5780                                    let debug_adapter =
 5781                                        language_settings(language.name().into(), file, cx)
 5782                                            .debuggers
 5783                                            .first()
 5784                                            .map(SharedString::from)
 5785                                            .or_else(|| {
 5786                                                language
 5787                                                    .config()
 5788                                                    .debuggers
 5789                                                    .first()
 5790                                                    .map(SharedString::from)
 5791                                            })?;
 5792
 5793                                    dap_store.update(cx, |dap_store, cx| {
 5794                                        for (_, task) in &resolved_tasks.templates {
 5795                                            if let Some(scenario) = dap_store
 5796                                                .debug_scenario_for_build_task(
 5797                                                    task.original_task().clone(),
 5798                                                    debug_adapter.clone().into(),
 5799                                                    task.display_label().to_owned().into(),
 5800                                                    cx,
 5801                                                )
 5802                                            {
 5803                                                scenarios.push(scenario);
 5804                                            }
 5805                                        }
 5806                                    });
 5807                                    Some(scenarios)
 5808                                })
 5809                                .unwrap_or_default()
 5810                            } else {
 5811                                vec![]
 5812                            }
 5813                        })?;
 5814                        let spawn_straight_away = quick_launch
 5815                            && resolved_tasks
 5816                                .as_ref()
 5817                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5818                            && code_actions
 5819                                .as_ref()
 5820                                .map_or(true, |actions| actions.is_empty())
 5821                            && debug_scenarios.is_empty();
 5822                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5823                            crate::hover_popover::hide_hover(editor, cx);
 5824                            *editor.context_menu.borrow_mut() =
 5825                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5826                                    buffer,
 5827                                    actions: CodeActionContents::new(
 5828                                        resolved_tasks,
 5829                                        code_actions,
 5830                                        debug_scenarios,
 5831                                        task_context.unwrap_or_default(),
 5832                                    ),
 5833                                    selected_item: Default::default(),
 5834                                    scroll_handle: UniformListScrollHandle::default(),
 5835                                    deployed_from,
 5836                                }));
 5837                            if spawn_straight_away {
 5838                                if let Some(task) = editor.confirm_code_action(
 5839                                    &ConfirmCodeAction { item_ix: Some(0) },
 5840                                    window,
 5841                                    cx,
 5842                                ) {
 5843                                    cx.notify();
 5844                                    return task;
 5845                                }
 5846                            }
 5847                            cx.notify();
 5848                            Task::ready(Ok(()))
 5849                        }) {
 5850                            task.await
 5851                        } else {
 5852                            Ok(())
 5853                        }
 5854                    }))
 5855                } else {
 5856                    Some(Task::ready(Ok(())))
 5857                }
 5858            })?;
 5859            if let Some(task) = spawned_test_task {
 5860                task.await?;
 5861            }
 5862
 5863            anyhow::Ok(())
 5864        })
 5865        .detach_and_log_err(cx);
 5866    }
 5867
 5868    pub fn confirm_code_action(
 5869        &mut self,
 5870        action: &ConfirmCodeAction,
 5871        window: &mut Window,
 5872        cx: &mut Context<Self>,
 5873    ) -> Option<Task<Result<()>>> {
 5874        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5875
 5876        let actions_menu =
 5877            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5878                menu
 5879            } else {
 5880                return None;
 5881            };
 5882
 5883        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5884        let action = actions_menu.actions.get(action_ix)?;
 5885        let title = action.label();
 5886        let buffer = actions_menu.buffer;
 5887        let workspace = self.workspace()?;
 5888
 5889        match action {
 5890            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5891                workspace.update(cx, |workspace, cx| {
 5892                    workspace.schedule_resolved_task(
 5893                        task_source_kind,
 5894                        resolved_task,
 5895                        false,
 5896                        window,
 5897                        cx,
 5898                    );
 5899
 5900                    Some(Task::ready(Ok(())))
 5901                })
 5902            }
 5903            CodeActionsItem::CodeAction {
 5904                excerpt_id,
 5905                action,
 5906                provider,
 5907            } => {
 5908                let apply_code_action =
 5909                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5910                let workspace = workspace.downgrade();
 5911                Some(cx.spawn_in(window, async move |editor, cx| {
 5912                    let project_transaction = apply_code_action.await?;
 5913                    Self::open_project_transaction(
 5914                        &editor,
 5915                        workspace,
 5916                        project_transaction,
 5917                        title,
 5918                        cx,
 5919                    )
 5920                    .await
 5921                }))
 5922            }
 5923            CodeActionsItem::DebugScenario(scenario) => {
 5924                let context = actions_menu.actions.context.clone();
 5925
 5926                workspace.update(cx, |workspace, cx| {
 5927                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5928                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5929                });
 5930                Some(Task::ready(Ok(())))
 5931            }
 5932        }
 5933    }
 5934
 5935    pub async fn open_project_transaction(
 5936        this: &WeakEntity<Editor>,
 5937        workspace: WeakEntity<Workspace>,
 5938        transaction: ProjectTransaction,
 5939        title: String,
 5940        cx: &mut AsyncWindowContext,
 5941    ) -> Result<()> {
 5942        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5943        cx.update(|_, cx| {
 5944            entries.sort_unstable_by_key(|(buffer, _)| {
 5945                buffer.read(cx).file().map(|f| f.path().clone())
 5946            });
 5947        })?;
 5948
 5949        // If the project transaction's edits are all contained within this editor, then
 5950        // avoid opening a new editor to display them.
 5951
 5952        if let Some((buffer, transaction)) = entries.first() {
 5953            if entries.len() == 1 {
 5954                let excerpt = this.update(cx, |editor, cx| {
 5955                    editor
 5956                        .buffer()
 5957                        .read(cx)
 5958                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5959                })?;
 5960                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5961                    if excerpted_buffer == *buffer {
 5962                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5963                            let excerpt_range = excerpt_range.to_offset(buffer);
 5964                            buffer
 5965                                .edited_ranges_for_transaction::<usize>(transaction)
 5966                                .all(|range| {
 5967                                    excerpt_range.start <= range.start
 5968                                        && excerpt_range.end >= range.end
 5969                                })
 5970                        })?;
 5971
 5972                        if all_edits_within_excerpt {
 5973                            return Ok(());
 5974                        }
 5975                    }
 5976                }
 5977            }
 5978        } else {
 5979            return Ok(());
 5980        }
 5981
 5982        let mut ranges_to_highlight = Vec::new();
 5983        let excerpt_buffer = cx.new(|cx| {
 5984            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5985            for (buffer_handle, transaction) in &entries {
 5986                let edited_ranges = buffer_handle
 5987                    .read(cx)
 5988                    .edited_ranges_for_transaction::<Point>(transaction)
 5989                    .collect::<Vec<_>>();
 5990                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5991                    PathKey::for_buffer(buffer_handle, cx),
 5992                    buffer_handle.clone(),
 5993                    edited_ranges,
 5994                    DEFAULT_MULTIBUFFER_CONTEXT,
 5995                    cx,
 5996                );
 5997
 5998                ranges_to_highlight.extend(ranges);
 5999            }
 6000            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6001            multibuffer
 6002        })?;
 6003
 6004        workspace.update_in(cx, |workspace, window, cx| {
 6005            let project = workspace.project().clone();
 6006            let editor =
 6007                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6008            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6009            editor.update(cx, |editor, cx| {
 6010                editor.highlight_background::<Self>(
 6011                    &ranges_to_highlight,
 6012                    |theme| theme.editor_highlighted_line_background,
 6013                    cx,
 6014                );
 6015            });
 6016        })?;
 6017
 6018        Ok(())
 6019    }
 6020
 6021    pub fn clear_code_action_providers(&mut self) {
 6022        self.code_action_providers.clear();
 6023        self.available_code_actions.take();
 6024    }
 6025
 6026    pub fn add_code_action_provider(
 6027        &mut self,
 6028        provider: Rc<dyn CodeActionProvider>,
 6029        window: &mut Window,
 6030        cx: &mut Context<Self>,
 6031    ) {
 6032        if self
 6033            .code_action_providers
 6034            .iter()
 6035            .any(|existing_provider| existing_provider.id() == provider.id())
 6036        {
 6037            return;
 6038        }
 6039
 6040        self.code_action_providers.push(provider);
 6041        self.refresh_code_actions(window, cx);
 6042    }
 6043
 6044    pub fn remove_code_action_provider(
 6045        &mut self,
 6046        id: Arc<str>,
 6047        window: &mut Window,
 6048        cx: &mut Context<Self>,
 6049    ) {
 6050        self.code_action_providers
 6051            .retain(|provider| provider.id() != id);
 6052        self.refresh_code_actions(window, cx);
 6053    }
 6054
 6055    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6056        !self.code_action_providers.is_empty()
 6057            && EditorSettings::get_global(cx).toolbar.code_actions
 6058    }
 6059
 6060    pub fn has_available_code_actions(&self) -> bool {
 6061        self.available_code_actions
 6062            .as_ref()
 6063            .is_some_and(|(_, actions)| !actions.is_empty())
 6064    }
 6065
 6066    fn render_inline_code_actions(
 6067        &self,
 6068        icon_size: ui::IconSize,
 6069        display_row: DisplayRow,
 6070        is_active: bool,
 6071        cx: &mut Context<Self>,
 6072    ) -> AnyElement {
 6073        let show_tooltip = !self.context_menu_visible();
 6074        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6075            .icon_size(icon_size)
 6076            .shape(ui::IconButtonShape::Square)
 6077            .style(ButtonStyle::Transparent)
 6078            .icon_color(ui::Color::Hidden)
 6079            .toggle_state(is_active)
 6080            .when(show_tooltip, |this| {
 6081                this.tooltip({
 6082                    let focus_handle = self.focus_handle.clone();
 6083                    move |window, cx| {
 6084                        Tooltip::for_action_in(
 6085                            "Toggle Code Actions",
 6086                            &ToggleCodeActions {
 6087                                deployed_from: None,
 6088                                quick_launch: false,
 6089                            },
 6090                            &focus_handle,
 6091                            window,
 6092                            cx,
 6093                        )
 6094                    }
 6095                })
 6096            })
 6097            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6098                window.focus(&editor.focus_handle(cx));
 6099                editor.toggle_code_actions(
 6100                    &crate::actions::ToggleCodeActions {
 6101                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6102                            display_row,
 6103                        )),
 6104                        quick_launch: false,
 6105                    },
 6106                    window,
 6107                    cx,
 6108                );
 6109            }))
 6110            .into_any_element()
 6111    }
 6112
 6113    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6114        &self.context_menu
 6115    }
 6116
 6117    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6118        let newest_selection = self.selections.newest_anchor().clone();
 6119        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6120        let buffer = self.buffer.read(cx);
 6121        if newest_selection.head().diff_base_anchor.is_some() {
 6122            return None;
 6123        }
 6124        let (start_buffer, start) =
 6125            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6126        let (end_buffer, end) =
 6127            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6128        if start_buffer != end_buffer {
 6129            return None;
 6130        }
 6131
 6132        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6133            cx.background_executor()
 6134                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6135                .await;
 6136
 6137            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6138                let providers = this.code_action_providers.clone();
 6139                let tasks = this
 6140                    .code_action_providers
 6141                    .iter()
 6142                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6143                    .collect::<Vec<_>>();
 6144                (providers, tasks)
 6145            })?;
 6146
 6147            let mut actions = Vec::new();
 6148            for (provider, provider_actions) in
 6149                providers.into_iter().zip(future::join_all(tasks).await)
 6150            {
 6151                if let Some(provider_actions) = provider_actions.log_err() {
 6152                    actions.extend(provider_actions.into_iter().map(|action| {
 6153                        AvailableCodeAction {
 6154                            excerpt_id: newest_selection.start.excerpt_id,
 6155                            action,
 6156                            provider: provider.clone(),
 6157                        }
 6158                    }));
 6159                }
 6160            }
 6161
 6162            this.update(cx, |this, cx| {
 6163                this.available_code_actions = if actions.is_empty() {
 6164                    None
 6165                } else {
 6166                    Some((
 6167                        Location {
 6168                            buffer: start_buffer,
 6169                            range: start..end,
 6170                        },
 6171                        actions.into(),
 6172                    ))
 6173                };
 6174                cx.notify();
 6175            })
 6176        }));
 6177        None
 6178    }
 6179
 6180    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6181        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6182            self.show_git_blame_inline = false;
 6183
 6184            self.show_git_blame_inline_delay_task =
 6185                Some(cx.spawn_in(window, async move |this, cx| {
 6186                    cx.background_executor().timer(delay).await;
 6187
 6188                    this.update(cx, |this, cx| {
 6189                        this.show_git_blame_inline = true;
 6190                        cx.notify();
 6191                    })
 6192                    .log_err();
 6193                }));
 6194        }
 6195    }
 6196
 6197    fn show_blame_popover(
 6198        &mut self,
 6199        blame_entry: &BlameEntry,
 6200        position: gpui::Point<Pixels>,
 6201        cx: &mut Context<Self>,
 6202    ) {
 6203        if let Some(state) = &mut self.inline_blame_popover {
 6204            state.hide_task.take();
 6205            cx.notify();
 6206        } else {
 6207            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6208            let show_task = cx.spawn(async move |editor, cx| {
 6209                cx.background_executor()
 6210                    .timer(std::time::Duration::from_millis(delay))
 6211                    .await;
 6212                editor
 6213                    .update(cx, |editor, cx| {
 6214                        if let Some(state) = &mut editor.inline_blame_popover {
 6215                            state.show_task = None;
 6216                            cx.notify();
 6217                        }
 6218                    })
 6219                    .ok();
 6220            });
 6221            let Some(blame) = self.blame.as_ref() else {
 6222                return;
 6223            };
 6224            let blame = blame.read(cx);
 6225            let details = blame.details_for_entry(&blame_entry);
 6226            let markdown = cx.new(|cx| {
 6227                Markdown::new(
 6228                    details
 6229                        .as_ref()
 6230                        .map(|message| message.message.clone())
 6231                        .unwrap_or_default(),
 6232                    None,
 6233                    None,
 6234                    cx,
 6235                )
 6236            });
 6237            self.inline_blame_popover = Some(InlineBlamePopover {
 6238                position,
 6239                show_task: Some(show_task),
 6240                hide_task: None,
 6241                popover_bounds: None,
 6242                popover_state: InlineBlamePopoverState {
 6243                    scroll_handle: ScrollHandle::new(),
 6244                    commit_message: details,
 6245                    markdown,
 6246                },
 6247            });
 6248        }
 6249    }
 6250
 6251    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6252        if let Some(state) = &mut self.inline_blame_popover {
 6253            if state.show_task.is_some() {
 6254                self.inline_blame_popover.take();
 6255                cx.notify();
 6256            } else {
 6257                let hide_task = cx.spawn(async move |editor, cx| {
 6258                    cx.background_executor()
 6259                        .timer(std::time::Duration::from_millis(100))
 6260                        .await;
 6261                    editor
 6262                        .update(cx, |editor, cx| {
 6263                            editor.inline_blame_popover.take();
 6264                            cx.notify();
 6265                        })
 6266                        .ok();
 6267                });
 6268                state.hide_task = Some(hide_task);
 6269            }
 6270        }
 6271    }
 6272
 6273    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6274        if self.pending_rename.is_some() {
 6275            return None;
 6276        }
 6277
 6278        let provider = self.semantics_provider.clone()?;
 6279        let buffer = self.buffer.read(cx);
 6280        let newest_selection = self.selections.newest_anchor().clone();
 6281        let cursor_position = newest_selection.head();
 6282        let (cursor_buffer, cursor_buffer_position) =
 6283            buffer.text_anchor_for_position(cursor_position, cx)?;
 6284        let (tail_buffer, tail_buffer_position) =
 6285            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6286        if cursor_buffer != tail_buffer {
 6287            return None;
 6288        }
 6289
 6290        let snapshot = cursor_buffer.read(cx).snapshot();
 6291        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6292        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6293        if start_word_range != end_word_range {
 6294            self.document_highlights_task.take();
 6295            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6296            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6297            return None;
 6298        }
 6299
 6300        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6301        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6302            cx.background_executor()
 6303                .timer(Duration::from_millis(debounce))
 6304                .await;
 6305
 6306            let highlights = if let Some(highlights) = cx
 6307                .update(|cx| {
 6308                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6309                })
 6310                .ok()
 6311                .flatten()
 6312            {
 6313                highlights.await.log_err()
 6314            } else {
 6315                None
 6316            };
 6317
 6318            if let Some(highlights) = highlights {
 6319                this.update(cx, |this, cx| {
 6320                    if this.pending_rename.is_some() {
 6321                        return;
 6322                    }
 6323
 6324                    let buffer_id = cursor_position.buffer_id;
 6325                    let buffer = this.buffer.read(cx);
 6326                    if !buffer
 6327                        .text_anchor_for_position(cursor_position, cx)
 6328                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6329                    {
 6330                        return;
 6331                    }
 6332
 6333                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6334                    let mut write_ranges = Vec::new();
 6335                    let mut read_ranges = Vec::new();
 6336                    for highlight in highlights {
 6337                        for (excerpt_id, excerpt_range) in
 6338                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6339                        {
 6340                            let start = highlight
 6341                                .range
 6342                                .start
 6343                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6344                            let end = highlight
 6345                                .range
 6346                                .end
 6347                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6348                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6349                                continue;
 6350                            }
 6351
 6352                            let range = Anchor {
 6353                                buffer_id,
 6354                                excerpt_id,
 6355                                text_anchor: start,
 6356                                diff_base_anchor: None,
 6357                            }..Anchor {
 6358                                buffer_id,
 6359                                excerpt_id,
 6360                                text_anchor: end,
 6361                                diff_base_anchor: None,
 6362                            };
 6363                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6364                                write_ranges.push(range);
 6365                            } else {
 6366                                read_ranges.push(range);
 6367                            }
 6368                        }
 6369                    }
 6370
 6371                    this.highlight_background::<DocumentHighlightRead>(
 6372                        &read_ranges,
 6373                        |theme| theme.editor_document_highlight_read_background,
 6374                        cx,
 6375                    );
 6376                    this.highlight_background::<DocumentHighlightWrite>(
 6377                        &write_ranges,
 6378                        |theme| theme.editor_document_highlight_write_background,
 6379                        cx,
 6380                    );
 6381                    cx.notify();
 6382                })
 6383                .log_err();
 6384            }
 6385        }));
 6386        None
 6387    }
 6388
 6389    fn prepare_highlight_query_from_selection(
 6390        &mut self,
 6391        cx: &mut Context<Editor>,
 6392    ) -> Option<(String, Range<Anchor>)> {
 6393        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6394            return None;
 6395        }
 6396        if !EditorSettings::get_global(cx).selection_highlight {
 6397            return None;
 6398        }
 6399        if self.selections.count() != 1 || self.selections.line_mode {
 6400            return None;
 6401        }
 6402        let selection = self.selections.newest::<Point>(cx);
 6403        if selection.is_empty() || selection.start.row != selection.end.row {
 6404            return None;
 6405        }
 6406        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6407        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6408        let query = multi_buffer_snapshot
 6409            .text_for_range(selection_anchor_range.clone())
 6410            .collect::<String>();
 6411        if query.trim().is_empty() {
 6412            return None;
 6413        }
 6414        Some((query, selection_anchor_range))
 6415    }
 6416
 6417    fn update_selection_occurrence_highlights(
 6418        &mut self,
 6419        query_text: String,
 6420        query_range: Range<Anchor>,
 6421        multi_buffer_range_to_query: Range<Point>,
 6422        use_debounce: bool,
 6423        window: &mut Window,
 6424        cx: &mut Context<Editor>,
 6425    ) -> Task<()> {
 6426        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6427        cx.spawn_in(window, async move |editor, cx| {
 6428            if use_debounce {
 6429                cx.background_executor()
 6430                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6431                    .await;
 6432            }
 6433            let match_task = cx.background_spawn(async move {
 6434                let buffer_ranges = multi_buffer_snapshot
 6435                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6436                    .into_iter()
 6437                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6438                let mut match_ranges = Vec::new();
 6439                let Ok(regex) = project::search::SearchQuery::text(
 6440                    query_text.clone(),
 6441                    false,
 6442                    false,
 6443                    false,
 6444                    Default::default(),
 6445                    Default::default(),
 6446                    false,
 6447                    None,
 6448                ) else {
 6449                    return Vec::default();
 6450                };
 6451                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6452                    match_ranges.extend(
 6453                        regex
 6454                            .search(&buffer_snapshot, Some(search_range.clone()))
 6455                            .await
 6456                            .into_iter()
 6457                            .filter_map(|match_range| {
 6458                                let match_start = buffer_snapshot
 6459                                    .anchor_after(search_range.start + match_range.start);
 6460                                let match_end = buffer_snapshot
 6461                                    .anchor_before(search_range.start + match_range.end);
 6462                                let match_anchor_range = Anchor::range_in_buffer(
 6463                                    excerpt_id,
 6464                                    buffer_snapshot.remote_id(),
 6465                                    match_start..match_end,
 6466                                );
 6467                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6468                            }),
 6469                    );
 6470                }
 6471                match_ranges
 6472            });
 6473            let match_ranges = match_task.await;
 6474            editor
 6475                .update_in(cx, |editor, _, cx| {
 6476                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6477                    if !match_ranges.is_empty() {
 6478                        editor.highlight_background::<SelectedTextHighlight>(
 6479                            &match_ranges,
 6480                            |theme| theme.editor_document_highlight_bracket_background,
 6481                            cx,
 6482                        )
 6483                    }
 6484                })
 6485                .log_err();
 6486        })
 6487    }
 6488
 6489    fn refresh_selected_text_highlights(
 6490        &mut self,
 6491        on_buffer_edit: bool,
 6492        window: &mut Window,
 6493        cx: &mut Context<Editor>,
 6494    ) {
 6495        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6496        else {
 6497            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6498            self.quick_selection_highlight_task.take();
 6499            self.debounced_selection_highlight_task.take();
 6500            return;
 6501        };
 6502        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6503        if on_buffer_edit
 6504            || self
 6505                .quick_selection_highlight_task
 6506                .as_ref()
 6507                .map_or(true, |(prev_anchor_range, _)| {
 6508                    prev_anchor_range != &query_range
 6509                })
 6510        {
 6511            let multi_buffer_visible_start = self
 6512                .scroll_manager
 6513                .anchor()
 6514                .anchor
 6515                .to_point(&multi_buffer_snapshot);
 6516            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6517                multi_buffer_visible_start
 6518                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6519                Bias::Left,
 6520            );
 6521            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6522            self.quick_selection_highlight_task = Some((
 6523                query_range.clone(),
 6524                self.update_selection_occurrence_highlights(
 6525                    query_text.clone(),
 6526                    query_range.clone(),
 6527                    multi_buffer_visible_range,
 6528                    false,
 6529                    window,
 6530                    cx,
 6531                ),
 6532            ));
 6533        }
 6534        if on_buffer_edit
 6535            || self
 6536                .debounced_selection_highlight_task
 6537                .as_ref()
 6538                .map_or(true, |(prev_anchor_range, _)| {
 6539                    prev_anchor_range != &query_range
 6540                })
 6541        {
 6542            let multi_buffer_start = multi_buffer_snapshot
 6543                .anchor_before(0)
 6544                .to_point(&multi_buffer_snapshot);
 6545            let multi_buffer_end = multi_buffer_snapshot
 6546                .anchor_after(multi_buffer_snapshot.len())
 6547                .to_point(&multi_buffer_snapshot);
 6548            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6549            self.debounced_selection_highlight_task = Some((
 6550                query_range.clone(),
 6551                self.update_selection_occurrence_highlights(
 6552                    query_text,
 6553                    query_range,
 6554                    multi_buffer_full_range,
 6555                    true,
 6556                    window,
 6557                    cx,
 6558                ),
 6559            ));
 6560        }
 6561    }
 6562
 6563    pub fn refresh_inline_completion(
 6564        &mut self,
 6565        debounce: bool,
 6566        user_requested: bool,
 6567        window: &mut Window,
 6568        cx: &mut Context<Self>,
 6569    ) -> Option<()> {
 6570        let provider = self.edit_prediction_provider()?;
 6571        let cursor = self.selections.newest_anchor().head();
 6572        let (buffer, cursor_buffer_position) =
 6573            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6574
 6575        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6576            self.discard_inline_completion(false, cx);
 6577            return None;
 6578        }
 6579
 6580        if !user_requested
 6581            && (!self.should_show_edit_predictions()
 6582                || !self.is_focused(window)
 6583                || buffer.read(cx).is_empty())
 6584        {
 6585            self.discard_inline_completion(false, cx);
 6586            return None;
 6587        }
 6588
 6589        self.update_visible_inline_completion(window, cx);
 6590        provider.refresh(
 6591            self.project.clone(),
 6592            buffer,
 6593            cursor_buffer_position,
 6594            debounce,
 6595            cx,
 6596        );
 6597        Some(())
 6598    }
 6599
 6600    fn show_edit_predictions_in_menu(&self) -> bool {
 6601        match self.edit_prediction_settings {
 6602            EditPredictionSettings::Disabled => false,
 6603            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6604        }
 6605    }
 6606
 6607    pub fn edit_predictions_enabled(&self) -> bool {
 6608        match self.edit_prediction_settings {
 6609            EditPredictionSettings::Disabled => false,
 6610            EditPredictionSettings::Enabled { .. } => true,
 6611        }
 6612    }
 6613
 6614    fn edit_prediction_requires_modifier(&self) -> bool {
 6615        match self.edit_prediction_settings {
 6616            EditPredictionSettings::Disabled => false,
 6617            EditPredictionSettings::Enabled {
 6618                preview_requires_modifier,
 6619                ..
 6620            } => preview_requires_modifier,
 6621        }
 6622    }
 6623
 6624    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6625        if self.edit_prediction_provider.is_none() {
 6626            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6627        } else {
 6628            let selection = self.selections.newest_anchor();
 6629            let cursor = selection.head();
 6630
 6631            if let Some((buffer, cursor_buffer_position)) =
 6632                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6633            {
 6634                self.edit_prediction_settings =
 6635                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6636            }
 6637        }
 6638    }
 6639
 6640    fn edit_prediction_settings_at_position(
 6641        &self,
 6642        buffer: &Entity<Buffer>,
 6643        buffer_position: language::Anchor,
 6644        cx: &App,
 6645    ) -> EditPredictionSettings {
 6646        if !self.mode.is_full()
 6647            || !self.show_inline_completions_override.unwrap_or(true)
 6648            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6649        {
 6650            return EditPredictionSettings::Disabled;
 6651        }
 6652
 6653        let buffer = buffer.read(cx);
 6654
 6655        let file = buffer.file();
 6656
 6657        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6658            return EditPredictionSettings::Disabled;
 6659        };
 6660
 6661        let by_provider = matches!(
 6662            self.menu_inline_completions_policy,
 6663            MenuInlineCompletionsPolicy::ByProvider
 6664        );
 6665
 6666        let show_in_menu = by_provider
 6667            && self
 6668                .edit_prediction_provider
 6669                .as_ref()
 6670                .map_or(false, |provider| {
 6671                    provider.provider.show_completions_in_menu()
 6672                });
 6673
 6674        let preview_requires_modifier =
 6675            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6676
 6677        EditPredictionSettings::Enabled {
 6678            show_in_menu,
 6679            preview_requires_modifier,
 6680        }
 6681    }
 6682
 6683    fn should_show_edit_predictions(&self) -> bool {
 6684        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6685    }
 6686
 6687    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6688        matches!(
 6689            self.edit_prediction_preview,
 6690            EditPredictionPreview::Active { .. }
 6691        )
 6692    }
 6693
 6694    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6695        let cursor = self.selections.newest_anchor().head();
 6696        if let Some((buffer, cursor_position)) =
 6697            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6698        {
 6699            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6700        } else {
 6701            false
 6702        }
 6703    }
 6704
 6705    pub fn supports_minimap(&self, cx: &App) -> bool {
 6706        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6707    }
 6708
 6709    fn edit_predictions_enabled_in_buffer(
 6710        &self,
 6711        buffer: &Entity<Buffer>,
 6712        buffer_position: language::Anchor,
 6713        cx: &App,
 6714    ) -> bool {
 6715        maybe!({
 6716            if self.read_only(cx) {
 6717                return Some(false);
 6718            }
 6719            let provider = self.edit_prediction_provider()?;
 6720            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6721                return Some(false);
 6722            }
 6723            let buffer = buffer.read(cx);
 6724            let Some(file) = buffer.file() else {
 6725                return Some(true);
 6726            };
 6727            let settings = all_language_settings(Some(file), cx);
 6728            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6729        })
 6730        .unwrap_or(false)
 6731    }
 6732
 6733    fn cycle_inline_completion(
 6734        &mut self,
 6735        direction: Direction,
 6736        window: &mut Window,
 6737        cx: &mut Context<Self>,
 6738    ) -> Option<()> {
 6739        let provider = self.edit_prediction_provider()?;
 6740        let cursor = self.selections.newest_anchor().head();
 6741        let (buffer, cursor_buffer_position) =
 6742            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6743        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6744            return None;
 6745        }
 6746
 6747        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6748        self.update_visible_inline_completion(window, cx);
 6749
 6750        Some(())
 6751    }
 6752
 6753    pub fn show_inline_completion(
 6754        &mut self,
 6755        _: &ShowEditPrediction,
 6756        window: &mut Window,
 6757        cx: &mut Context<Self>,
 6758    ) {
 6759        if !self.has_active_inline_completion() {
 6760            self.refresh_inline_completion(false, true, window, cx);
 6761            return;
 6762        }
 6763
 6764        self.update_visible_inline_completion(window, cx);
 6765    }
 6766
 6767    pub fn display_cursor_names(
 6768        &mut self,
 6769        _: &DisplayCursorNames,
 6770        window: &mut Window,
 6771        cx: &mut Context<Self>,
 6772    ) {
 6773        self.show_cursor_names(window, cx);
 6774    }
 6775
 6776    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6777        self.show_cursor_names = true;
 6778        cx.notify();
 6779        cx.spawn_in(window, async move |this, cx| {
 6780            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6781            this.update(cx, |this, cx| {
 6782                this.show_cursor_names = false;
 6783                cx.notify()
 6784            })
 6785            .ok()
 6786        })
 6787        .detach();
 6788    }
 6789
 6790    pub fn next_edit_prediction(
 6791        &mut self,
 6792        _: &NextEditPrediction,
 6793        window: &mut Window,
 6794        cx: &mut Context<Self>,
 6795    ) {
 6796        if self.has_active_inline_completion() {
 6797            self.cycle_inline_completion(Direction::Next, window, cx);
 6798        } else {
 6799            let is_copilot_disabled = self
 6800                .refresh_inline_completion(false, true, window, cx)
 6801                .is_none();
 6802            if is_copilot_disabled {
 6803                cx.propagate();
 6804            }
 6805        }
 6806    }
 6807
 6808    pub fn previous_edit_prediction(
 6809        &mut self,
 6810        _: &PreviousEditPrediction,
 6811        window: &mut Window,
 6812        cx: &mut Context<Self>,
 6813    ) {
 6814        if self.has_active_inline_completion() {
 6815            self.cycle_inline_completion(Direction::Prev, window, cx);
 6816        } else {
 6817            let is_copilot_disabled = self
 6818                .refresh_inline_completion(false, true, window, cx)
 6819                .is_none();
 6820            if is_copilot_disabled {
 6821                cx.propagate();
 6822            }
 6823        }
 6824    }
 6825
 6826    pub fn accept_edit_prediction(
 6827        &mut self,
 6828        _: &AcceptEditPrediction,
 6829        window: &mut Window,
 6830        cx: &mut Context<Self>,
 6831    ) {
 6832        if self.show_edit_predictions_in_menu() {
 6833            self.hide_context_menu(window, cx);
 6834        }
 6835
 6836        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6837            return;
 6838        };
 6839
 6840        self.report_inline_completion_event(
 6841            active_inline_completion.completion_id.clone(),
 6842            true,
 6843            cx,
 6844        );
 6845
 6846        match &active_inline_completion.completion {
 6847            InlineCompletion::Move { target, .. } => {
 6848                let target = *target;
 6849
 6850                if let Some(position_map) = &self.last_position_map {
 6851                    if position_map
 6852                        .visible_row_range
 6853                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6854                        || !self.edit_prediction_requires_modifier()
 6855                    {
 6856                        self.unfold_ranges(&[target..target], true, false, cx);
 6857                        // Note that this is also done in vim's handler of the Tab action.
 6858                        self.change_selections(
 6859                            Some(Autoscroll::newest()),
 6860                            window,
 6861                            cx,
 6862                            |selections| {
 6863                                selections.select_anchor_ranges([target..target]);
 6864                            },
 6865                        );
 6866                        self.clear_row_highlights::<EditPredictionPreview>();
 6867
 6868                        self.edit_prediction_preview
 6869                            .set_previous_scroll_position(None);
 6870                    } else {
 6871                        self.edit_prediction_preview
 6872                            .set_previous_scroll_position(Some(
 6873                                position_map.snapshot.scroll_anchor,
 6874                            ));
 6875
 6876                        self.highlight_rows::<EditPredictionPreview>(
 6877                            target..target,
 6878                            cx.theme().colors().editor_highlighted_line_background,
 6879                            RowHighlightOptions {
 6880                                autoscroll: true,
 6881                                ..Default::default()
 6882                            },
 6883                            cx,
 6884                        );
 6885                        self.request_autoscroll(Autoscroll::fit(), cx);
 6886                    }
 6887                }
 6888            }
 6889            InlineCompletion::Edit { edits, .. } => {
 6890                if let Some(provider) = self.edit_prediction_provider() {
 6891                    provider.accept(cx);
 6892                }
 6893
 6894                // Store the transaction ID and selections before applying the edit
 6895                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6896
 6897                let snapshot = self.buffer.read(cx).snapshot(cx);
 6898                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6899
 6900                self.buffer.update(cx, |buffer, cx| {
 6901                    buffer.edit(edits.iter().cloned(), None, cx)
 6902                });
 6903
 6904                self.change_selections(None, window, cx, |s| {
 6905                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6906                });
 6907
 6908                let selections = self.selections.disjoint_anchors();
 6909                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6910                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6911                    if has_new_transaction {
 6912                        self.selection_history
 6913                            .insert_transaction(transaction_id_now, selections);
 6914                    }
 6915                }
 6916
 6917                self.update_visible_inline_completion(window, cx);
 6918                if self.active_inline_completion.is_none() {
 6919                    self.refresh_inline_completion(true, true, window, cx);
 6920                }
 6921
 6922                cx.notify();
 6923            }
 6924        }
 6925
 6926        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6927    }
 6928
 6929    pub fn accept_partial_inline_completion(
 6930        &mut self,
 6931        _: &AcceptPartialEditPrediction,
 6932        window: &mut Window,
 6933        cx: &mut Context<Self>,
 6934    ) {
 6935        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6936            return;
 6937        };
 6938        if self.selections.count() != 1 {
 6939            return;
 6940        }
 6941
 6942        self.report_inline_completion_event(
 6943            active_inline_completion.completion_id.clone(),
 6944            true,
 6945            cx,
 6946        );
 6947
 6948        match &active_inline_completion.completion {
 6949            InlineCompletion::Move { target, .. } => {
 6950                let target = *target;
 6951                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6952                    selections.select_anchor_ranges([target..target]);
 6953                });
 6954            }
 6955            InlineCompletion::Edit { edits, .. } => {
 6956                // Find an insertion that starts at the cursor position.
 6957                let snapshot = self.buffer.read(cx).snapshot(cx);
 6958                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6959                let insertion = edits.iter().find_map(|(range, text)| {
 6960                    let range = range.to_offset(&snapshot);
 6961                    if range.is_empty() && range.start == cursor_offset {
 6962                        Some(text)
 6963                    } else {
 6964                        None
 6965                    }
 6966                });
 6967
 6968                if let Some(text) = insertion {
 6969                    let mut partial_completion = text
 6970                        .chars()
 6971                        .by_ref()
 6972                        .take_while(|c| c.is_alphabetic())
 6973                        .collect::<String>();
 6974                    if partial_completion.is_empty() {
 6975                        partial_completion = text
 6976                            .chars()
 6977                            .by_ref()
 6978                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6979                            .collect::<String>();
 6980                    }
 6981
 6982                    cx.emit(EditorEvent::InputHandled {
 6983                        utf16_range_to_replace: None,
 6984                        text: partial_completion.clone().into(),
 6985                    });
 6986
 6987                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6988
 6989                    self.refresh_inline_completion(true, true, window, cx);
 6990                    cx.notify();
 6991                } else {
 6992                    self.accept_edit_prediction(&Default::default(), window, cx);
 6993                }
 6994            }
 6995        }
 6996    }
 6997
 6998    fn discard_inline_completion(
 6999        &mut self,
 7000        should_report_inline_completion_event: bool,
 7001        cx: &mut Context<Self>,
 7002    ) -> bool {
 7003        if should_report_inline_completion_event {
 7004            let completion_id = self
 7005                .active_inline_completion
 7006                .as_ref()
 7007                .and_then(|active_completion| active_completion.completion_id.clone());
 7008
 7009            self.report_inline_completion_event(completion_id, false, cx);
 7010        }
 7011
 7012        if let Some(provider) = self.edit_prediction_provider() {
 7013            provider.discard(cx);
 7014        }
 7015
 7016        self.take_active_inline_completion(cx)
 7017    }
 7018
 7019    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7020        let Some(provider) = self.edit_prediction_provider() else {
 7021            return;
 7022        };
 7023
 7024        let Some((_, buffer, _)) = self
 7025            .buffer
 7026            .read(cx)
 7027            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7028        else {
 7029            return;
 7030        };
 7031
 7032        let extension = buffer
 7033            .read(cx)
 7034            .file()
 7035            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7036
 7037        let event_type = match accepted {
 7038            true => "Edit Prediction Accepted",
 7039            false => "Edit Prediction Discarded",
 7040        };
 7041        telemetry::event!(
 7042            event_type,
 7043            provider = provider.name(),
 7044            prediction_id = id,
 7045            suggestion_accepted = accepted,
 7046            file_extension = extension,
 7047        );
 7048    }
 7049
 7050    pub fn has_active_inline_completion(&self) -> bool {
 7051        self.active_inline_completion.is_some()
 7052    }
 7053
 7054    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7055        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7056            return false;
 7057        };
 7058
 7059        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7060        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7061        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7062        true
 7063    }
 7064
 7065    /// Returns true when we're displaying the edit prediction popover below the cursor
 7066    /// like we are not previewing and the LSP autocomplete menu is visible
 7067    /// or we are in `when_holding_modifier` mode.
 7068    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7069        if self.edit_prediction_preview_is_active()
 7070            || !self.show_edit_predictions_in_menu()
 7071            || !self.edit_predictions_enabled()
 7072        {
 7073            return false;
 7074        }
 7075
 7076        if self.has_visible_completions_menu() {
 7077            return true;
 7078        }
 7079
 7080        has_completion && self.edit_prediction_requires_modifier()
 7081    }
 7082
 7083    fn handle_modifiers_changed(
 7084        &mut self,
 7085        modifiers: Modifiers,
 7086        position_map: &PositionMap,
 7087        window: &mut Window,
 7088        cx: &mut Context<Self>,
 7089    ) {
 7090        if self.show_edit_predictions_in_menu() {
 7091            self.update_edit_prediction_preview(&modifiers, window, cx);
 7092        }
 7093
 7094        self.update_selection_mode(&modifiers, position_map, window, cx);
 7095
 7096        let mouse_position = window.mouse_position();
 7097        if !position_map.text_hitbox.is_hovered(window) {
 7098            return;
 7099        }
 7100
 7101        self.update_hovered_link(
 7102            position_map.point_for_position(mouse_position),
 7103            &position_map.snapshot,
 7104            modifiers,
 7105            window,
 7106            cx,
 7107        )
 7108    }
 7109
 7110    fn multi_cursor_modifier(
 7111        cursor_event: bool,
 7112        modifiers: &Modifiers,
 7113        cx: &mut Context<Self>,
 7114    ) -> bool {
 7115        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7116        if cursor_event {
 7117            match multi_cursor_setting {
 7118                MultiCursorModifier::Alt => modifiers.alt,
 7119                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7120            }
 7121        } else {
 7122            match multi_cursor_setting {
 7123                MultiCursorModifier::Alt => modifiers.secondary(),
 7124                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7125            }
 7126        }
 7127    }
 7128
 7129    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7130        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7131    }
 7132
 7133    fn update_selection_mode(
 7134        &mut self,
 7135        modifiers: &Modifiers,
 7136        position_map: &PositionMap,
 7137        window: &mut Window,
 7138        cx: &mut Context<Self>,
 7139    ) {
 7140        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7141        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7142            || self.selections.pending.is_none()
 7143        {
 7144            return;
 7145        }
 7146
 7147        let mouse_position = window.mouse_position();
 7148        let point_for_position = position_map.point_for_position(mouse_position);
 7149        let position = point_for_position.previous_valid;
 7150
 7151        self.select(
 7152            SelectPhase::BeginColumnar {
 7153                position,
 7154                reset: false,
 7155                goal_column: point_for_position.exact_unclipped.column(),
 7156            },
 7157            window,
 7158            cx,
 7159        );
 7160    }
 7161
 7162    fn update_edit_prediction_preview(
 7163        &mut self,
 7164        modifiers: &Modifiers,
 7165        window: &mut Window,
 7166        cx: &mut Context<Self>,
 7167    ) {
 7168        let mut modifiers_held = false;
 7169        if let Some(accept_keystroke) = self
 7170            .accept_edit_prediction_keybind(false, window, cx)
 7171            .keystroke()
 7172        {
 7173            modifiers_held = modifiers_held
 7174                || (&accept_keystroke.modifiers == modifiers
 7175                    && accept_keystroke.modifiers.modified());
 7176        };
 7177        if let Some(accept_partial_keystroke) = self
 7178            .accept_edit_prediction_keybind(true, window, cx)
 7179            .keystroke()
 7180        {
 7181            modifiers_held = modifiers_held
 7182                || (&accept_partial_keystroke.modifiers == modifiers
 7183                    && accept_partial_keystroke.modifiers.modified());
 7184        }
 7185
 7186        if modifiers_held {
 7187            if matches!(
 7188                self.edit_prediction_preview,
 7189                EditPredictionPreview::Inactive { .. }
 7190            ) {
 7191                self.edit_prediction_preview = EditPredictionPreview::Active {
 7192                    previous_scroll_position: None,
 7193                    since: Instant::now(),
 7194                };
 7195
 7196                self.update_visible_inline_completion(window, cx);
 7197                cx.notify();
 7198            }
 7199        } else if let EditPredictionPreview::Active {
 7200            previous_scroll_position,
 7201            since,
 7202        } = self.edit_prediction_preview
 7203        {
 7204            if let (Some(previous_scroll_position), Some(position_map)) =
 7205                (previous_scroll_position, self.last_position_map.as_ref())
 7206            {
 7207                self.set_scroll_position(
 7208                    previous_scroll_position
 7209                        .scroll_position(&position_map.snapshot.display_snapshot),
 7210                    window,
 7211                    cx,
 7212                );
 7213            }
 7214
 7215            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7216                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7217            };
 7218            self.clear_row_highlights::<EditPredictionPreview>();
 7219            self.update_visible_inline_completion(window, cx);
 7220            cx.notify();
 7221        }
 7222    }
 7223
 7224    fn update_visible_inline_completion(
 7225        &mut self,
 7226        _window: &mut Window,
 7227        cx: &mut Context<Self>,
 7228    ) -> Option<()> {
 7229        let selection = self.selections.newest_anchor();
 7230        let cursor = selection.head();
 7231        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7232        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7233        let excerpt_id = cursor.excerpt_id;
 7234
 7235        let show_in_menu = self.show_edit_predictions_in_menu();
 7236        let completions_menu_has_precedence = !show_in_menu
 7237            && (self.context_menu.borrow().is_some()
 7238                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7239
 7240        if completions_menu_has_precedence
 7241            || !offset_selection.is_empty()
 7242            || self
 7243                .active_inline_completion
 7244                .as_ref()
 7245                .map_or(false, |completion| {
 7246                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7247                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7248                    !invalidation_range.contains(&offset_selection.head())
 7249                })
 7250        {
 7251            self.discard_inline_completion(false, cx);
 7252            return None;
 7253        }
 7254
 7255        self.take_active_inline_completion(cx);
 7256        let Some(provider) = self.edit_prediction_provider() else {
 7257            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7258            return None;
 7259        };
 7260
 7261        let (buffer, cursor_buffer_position) =
 7262            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7263
 7264        self.edit_prediction_settings =
 7265            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7266
 7267        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7268
 7269        if self.edit_prediction_indent_conflict {
 7270            let cursor_point = cursor.to_point(&multibuffer);
 7271
 7272            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7273
 7274            if let Some((_, indent)) = indents.iter().next() {
 7275                if indent.len == cursor_point.column {
 7276                    self.edit_prediction_indent_conflict = false;
 7277                }
 7278            }
 7279        }
 7280
 7281        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7282        let edits = inline_completion
 7283            .edits
 7284            .into_iter()
 7285            .flat_map(|(range, new_text)| {
 7286                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7287                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7288                Some((start..end, new_text))
 7289            })
 7290            .collect::<Vec<_>>();
 7291        if edits.is_empty() {
 7292            return None;
 7293        }
 7294
 7295        let first_edit_start = edits.first().unwrap().0.start;
 7296        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7297        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7298
 7299        let last_edit_end = edits.last().unwrap().0.end;
 7300        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7301        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7302
 7303        let cursor_row = cursor.to_point(&multibuffer).row;
 7304
 7305        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7306
 7307        let mut inlay_ids = Vec::new();
 7308        let invalidation_row_range;
 7309        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7310            Some(cursor_row..edit_end_row)
 7311        } else if cursor_row > edit_end_row {
 7312            Some(edit_start_row..cursor_row)
 7313        } else {
 7314            None
 7315        };
 7316        let is_move =
 7317            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7318        let completion = if is_move {
 7319            invalidation_row_range =
 7320                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7321            let target = first_edit_start;
 7322            InlineCompletion::Move { target, snapshot }
 7323        } else {
 7324            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7325                && !self.inline_completions_hidden_for_vim_mode;
 7326
 7327            if show_completions_in_buffer {
 7328                if edits
 7329                    .iter()
 7330                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7331                {
 7332                    let mut inlays = Vec::new();
 7333                    for (range, new_text) in &edits {
 7334                        let inlay = Inlay::inline_completion(
 7335                            post_inc(&mut self.next_inlay_id),
 7336                            range.start,
 7337                            new_text.as_str(),
 7338                        );
 7339                        inlay_ids.push(inlay.id);
 7340                        inlays.push(inlay);
 7341                    }
 7342
 7343                    self.splice_inlays(&[], inlays, cx);
 7344                } else {
 7345                    let background_color = cx.theme().status().deleted_background;
 7346                    self.highlight_text::<InlineCompletionHighlight>(
 7347                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7348                        HighlightStyle {
 7349                            background_color: Some(background_color),
 7350                            ..Default::default()
 7351                        },
 7352                        cx,
 7353                    );
 7354                }
 7355            }
 7356
 7357            invalidation_row_range = edit_start_row..edit_end_row;
 7358
 7359            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7360                if provider.show_tab_accept_marker() {
 7361                    EditDisplayMode::TabAccept
 7362                } else {
 7363                    EditDisplayMode::Inline
 7364                }
 7365            } else {
 7366                EditDisplayMode::DiffPopover
 7367            };
 7368
 7369            InlineCompletion::Edit {
 7370                edits,
 7371                edit_preview: inline_completion.edit_preview,
 7372                display_mode,
 7373                snapshot,
 7374            }
 7375        };
 7376
 7377        let invalidation_range = multibuffer
 7378            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7379            ..multibuffer.anchor_after(Point::new(
 7380                invalidation_row_range.end,
 7381                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7382            ));
 7383
 7384        self.stale_inline_completion_in_menu = None;
 7385        self.active_inline_completion = Some(InlineCompletionState {
 7386            inlay_ids,
 7387            completion,
 7388            completion_id: inline_completion.id,
 7389            invalidation_range,
 7390        });
 7391
 7392        cx.notify();
 7393
 7394        Some(())
 7395    }
 7396
 7397    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7398        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7399    }
 7400
 7401    fn clear_tasks(&mut self) {
 7402        self.tasks.clear()
 7403    }
 7404
 7405    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7406        if self.tasks.insert(key, value).is_some() {
 7407            // This case should hopefully be rare, but just in case...
 7408            log::error!(
 7409                "multiple different run targets found on a single line, only the last target will be rendered"
 7410            )
 7411        }
 7412    }
 7413
 7414    /// Get all display points of breakpoints that will be rendered within editor
 7415    ///
 7416    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7417    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7418    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7419    fn active_breakpoints(
 7420        &self,
 7421        range: Range<DisplayRow>,
 7422        window: &mut Window,
 7423        cx: &mut Context<Self>,
 7424    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7425        let mut breakpoint_display_points = HashMap::default();
 7426
 7427        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7428            return breakpoint_display_points;
 7429        };
 7430
 7431        let snapshot = self.snapshot(window, cx);
 7432
 7433        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7434        let Some(project) = self.project.as_ref() else {
 7435            return breakpoint_display_points;
 7436        };
 7437
 7438        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7439            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7440
 7441        for (buffer_snapshot, range, excerpt_id) in
 7442            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7443        {
 7444            let Some(buffer) = project
 7445                .read(cx)
 7446                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7447            else {
 7448                continue;
 7449            };
 7450            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7451                &buffer,
 7452                Some(
 7453                    buffer_snapshot.anchor_before(range.start)
 7454                        ..buffer_snapshot.anchor_after(range.end),
 7455                ),
 7456                buffer_snapshot,
 7457                cx,
 7458            );
 7459            for (breakpoint, state) in breakpoints {
 7460                let multi_buffer_anchor =
 7461                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7462                let position = multi_buffer_anchor
 7463                    .to_point(&multi_buffer_snapshot)
 7464                    .to_display_point(&snapshot);
 7465
 7466                breakpoint_display_points.insert(
 7467                    position.row(),
 7468                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7469                );
 7470            }
 7471        }
 7472
 7473        breakpoint_display_points
 7474    }
 7475
 7476    fn breakpoint_context_menu(
 7477        &self,
 7478        anchor: Anchor,
 7479        window: &mut Window,
 7480        cx: &mut Context<Self>,
 7481    ) -> Entity<ui::ContextMenu> {
 7482        let weak_editor = cx.weak_entity();
 7483        let focus_handle = self.focus_handle(cx);
 7484
 7485        let row = self
 7486            .buffer
 7487            .read(cx)
 7488            .snapshot(cx)
 7489            .summary_for_anchor::<Point>(&anchor)
 7490            .row;
 7491
 7492        let breakpoint = self
 7493            .breakpoint_at_row(row, window, cx)
 7494            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7495
 7496        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7497            "Edit Log Breakpoint"
 7498        } else {
 7499            "Set Log Breakpoint"
 7500        };
 7501
 7502        let condition_breakpoint_msg = if breakpoint
 7503            .as_ref()
 7504            .is_some_and(|bp| bp.1.condition.is_some())
 7505        {
 7506            "Edit Condition Breakpoint"
 7507        } else {
 7508            "Set Condition Breakpoint"
 7509        };
 7510
 7511        let hit_condition_breakpoint_msg = if breakpoint
 7512            .as_ref()
 7513            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7514        {
 7515            "Edit Hit Condition Breakpoint"
 7516        } else {
 7517            "Set Hit Condition Breakpoint"
 7518        };
 7519
 7520        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7521            "Unset Breakpoint"
 7522        } else {
 7523            "Set Breakpoint"
 7524        };
 7525
 7526        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7527            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7528
 7529        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7530            BreakpointState::Enabled => Some("Disable"),
 7531            BreakpointState::Disabled => Some("Enable"),
 7532        });
 7533
 7534        let (anchor, breakpoint) =
 7535            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7536
 7537        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7538            menu.on_blur_subscription(Subscription::new(|| {}))
 7539                .context(focus_handle)
 7540                .when(run_to_cursor, |this| {
 7541                    let weak_editor = weak_editor.clone();
 7542                    this.entry("Run to cursor", None, move |window, cx| {
 7543                        weak_editor
 7544                            .update(cx, |editor, cx| {
 7545                                editor.change_selections(None, window, cx, |s| {
 7546                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7547                                });
 7548                            })
 7549                            .ok();
 7550
 7551                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7552                    })
 7553                    .separator()
 7554                })
 7555                .when_some(toggle_state_msg, |this, msg| {
 7556                    this.entry(msg, None, {
 7557                        let weak_editor = weak_editor.clone();
 7558                        let breakpoint = breakpoint.clone();
 7559                        move |_window, cx| {
 7560                            weak_editor
 7561                                .update(cx, |this, cx| {
 7562                                    this.edit_breakpoint_at_anchor(
 7563                                        anchor,
 7564                                        breakpoint.as_ref().clone(),
 7565                                        BreakpointEditAction::InvertState,
 7566                                        cx,
 7567                                    );
 7568                                })
 7569                                .log_err();
 7570                        }
 7571                    })
 7572                })
 7573                .entry(set_breakpoint_msg, None, {
 7574                    let weak_editor = weak_editor.clone();
 7575                    let breakpoint = breakpoint.clone();
 7576                    move |_window, cx| {
 7577                        weak_editor
 7578                            .update(cx, |this, cx| {
 7579                                this.edit_breakpoint_at_anchor(
 7580                                    anchor,
 7581                                    breakpoint.as_ref().clone(),
 7582                                    BreakpointEditAction::Toggle,
 7583                                    cx,
 7584                                );
 7585                            })
 7586                            .log_err();
 7587                    }
 7588                })
 7589                .entry(log_breakpoint_msg, None, {
 7590                    let breakpoint = breakpoint.clone();
 7591                    let weak_editor = weak_editor.clone();
 7592                    move |window, cx| {
 7593                        weak_editor
 7594                            .update(cx, |this, cx| {
 7595                                this.add_edit_breakpoint_block(
 7596                                    anchor,
 7597                                    breakpoint.as_ref(),
 7598                                    BreakpointPromptEditAction::Log,
 7599                                    window,
 7600                                    cx,
 7601                                );
 7602                            })
 7603                            .log_err();
 7604                    }
 7605                })
 7606                .entry(condition_breakpoint_msg, None, {
 7607                    let breakpoint = breakpoint.clone();
 7608                    let weak_editor = weak_editor.clone();
 7609                    move |window, cx| {
 7610                        weak_editor
 7611                            .update(cx, |this, cx| {
 7612                                this.add_edit_breakpoint_block(
 7613                                    anchor,
 7614                                    breakpoint.as_ref(),
 7615                                    BreakpointPromptEditAction::Condition,
 7616                                    window,
 7617                                    cx,
 7618                                );
 7619                            })
 7620                            .log_err();
 7621                    }
 7622                })
 7623                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7624                    weak_editor
 7625                        .update(cx, |this, cx| {
 7626                            this.add_edit_breakpoint_block(
 7627                                anchor,
 7628                                breakpoint.as_ref(),
 7629                                BreakpointPromptEditAction::HitCondition,
 7630                                window,
 7631                                cx,
 7632                            );
 7633                        })
 7634                        .log_err();
 7635                })
 7636        })
 7637    }
 7638
 7639    fn render_breakpoint(
 7640        &self,
 7641        position: Anchor,
 7642        row: DisplayRow,
 7643        breakpoint: &Breakpoint,
 7644        state: Option<BreakpointSessionState>,
 7645        cx: &mut Context<Self>,
 7646    ) -> IconButton {
 7647        let is_rejected = state.is_some_and(|s| !s.verified);
 7648        // Is it a breakpoint that shows up when hovering over gutter?
 7649        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7650            (false, false),
 7651            |PhantomBreakpointIndicator {
 7652                 is_active,
 7653                 display_row,
 7654                 collides_with_existing_breakpoint,
 7655             }| {
 7656                (
 7657                    is_active && display_row == row,
 7658                    collides_with_existing_breakpoint,
 7659                )
 7660            },
 7661        );
 7662
 7663        let (color, icon) = {
 7664            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7665                (false, false) => ui::IconName::DebugBreakpoint,
 7666                (true, false) => ui::IconName::DebugLogBreakpoint,
 7667                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7668                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7669            };
 7670
 7671            let color = if is_phantom {
 7672                Color::Hint
 7673            } else if is_rejected {
 7674                Color::Disabled
 7675            } else {
 7676                Color::Debugger
 7677            };
 7678
 7679            (color, icon)
 7680        };
 7681
 7682        let breakpoint = Arc::from(breakpoint.clone());
 7683
 7684        let alt_as_text = gpui::Keystroke {
 7685            modifiers: Modifiers::secondary_key(),
 7686            ..Default::default()
 7687        };
 7688        let primary_action_text = if breakpoint.is_disabled() {
 7689            "Enable breakpoint"
 7690        } else if is_phantom && !collides_with_existing {
 7691            "Set breakpoint"
 7692        } else {
 7693            "Unset breakpoint"
 7694        };
 7695        let focus_handle = self.focus_handle.clone();
 7696
 7697        let meta = if is_rejected {
 7698            SharedString::from("No executable code is associated with this line.")
 7699        } else if collides_with_existing && !breakpoint.is_disabled() {
 7700            SharedString::from(format!(
 7701                "{alt_as_text}-click to disable,\nright-click for more options."
 7702            ))
 7703        } else {
 7704            SharedString::from("Right-click for more options.")
 7705        };
 7706        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7707            .icon_size(IconSize::XSmall)
 7708            .size(ui::ButtonSize::None)
 7709            .when(is_rejected, |this| {
 7710                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7711            })
 7712            .icon_color(color)
 7713            .style(ButtonStyle::Transparent)
 7714            .on_click(cx.listener({
 7715                let breakpoint = breakpoint.clone();
 7716
 7717                move |editor, event: &ClickEvent, window, cx| {
 7718                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7719                        BreakpointEditAction::InvertState
 7720                    } else {
 7721                        BreakpointEditAction::Toggle
 7722                    };
 7723
 7724                    window.focus(&editor.focus_handle(cx));
 7725                    editor.edit_breakpoint_at_anchor(
 7726                        position,
 7727                        breakpoint.as_ref().clone(),
 7728                        edit_action,
 7729                        cx,
 7730                    );
 7731                }
 7732            }))
 7733            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7734                editor.set_breakpoint_context_menu(
 7735                    row,
 7736                    Some(position),
 7737                    event.down.position,
 7738                    window,
 7739                    cx,
 7740                );
 7741            }))
 7742            .tooltip(move |window, cx| {
 7743                Tooltip::with_meta_in(
 7744                    primary_action_text,
 7745                    Some(&ToggleBreakpoint),
 7746                    meta.clone(),
 7747                    &focus_handle,
 7748                    window,
 7749                    cx,
 7750                )
 7751            })
 7752    }
 7753
 7754    fn build_tasks_context(
 7755        project: &Entity<Project>,
 7756        buffer: &Entity<Buffer>,
 7757        buffer_row: u32,
 7758        tasks: &Arc<RunnableTasks>,
 7759        cx: &mut Context<Self>,
 7760    ) -> Task<Option<task::TaskContext>> {
 7761        let position = Point::new(buffer_row, tasks.column);
 7762        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7763        let location = Location {
 7764            buffer: buffer.clone(),
 7765            range: range_start..range_start,
 7766        };
 7767        // Fill in the environmental variables from the tree-sitter captures
 7768        let mut captured_task_variables = TaskVariables::default();
 7769        for (capture_name, value) in tasks.extra_variables.clone() {
 7770            captured_task_variables.insert(
 7771                task::VariableName::Custom(capture_name.into()),
 7772                value.clone(),
 7773            );
 7774        }
 7775        project.update(cx, |project, cx| {
 7776            project.task_store().update(cx, |task_store, cx| {
 7777                task_store.task_context_for_location(captured_task_variables, location, cx)
 7778            })
 7779        })
 7780    }
 7781
 7782    pub fn spawn_nearest_task(
 7783        &mut self,
 7784        action: &SpawnNearestTask,
 7785        window: &mut Window,
 7786        cx: &mut Context<Self>,
 7787    ) {
 7788        let Some((workspace, _)) = self.workspace.clone() else {
 7789            return;
 7790        };
 7791        let Some(project) = self.project.clone() else {
 7792            return;
 7793        };
 7794
 7795        // Try to find a closest, enclosing node using tree-sitter that has a
 7796        // task
 7797        let Some((buffer, buffer_row, tasks)) = self
 7798            .find_enclosing_node_task(cx)
 7799            // Or find the task that's closest in row-distance.
 7800            .or_else(|| self.find_closest_task(cx))
 7801        else {
 7802            return;
 7803        };
 7804
 7805        let reveal_strategy = action.reveal;
 7806        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7807        cx.spawn_in(window, async move |_, cx| {
 7808            let context = task_context.await?;
 7809            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7810
 7811            let resolved = &mut resolved_task.resolved;
 7812            resolved.reveal = reveal_strategy;
 7813
 7814            workspace
 7815                .update_in(cx, |workspace, window, cx| {
 7816                    workspace.schedule_resolved_task(
 7817                        task_source_kind,
 7818                        resolved_task,
 7819                        false,
 7820                        window,
 7821                        cx,
 7822                    );
 7823                })
 7824                .ok()
 7825        })
 7826        .detach();
 7827    }
 7828
 7829    fn find_closest_task(
 7830        &mut self,
 7831        cx: &mut Context<Self>,
 7832    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7833        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7834
 7835        let ((buffer_id, row), tasks) = self
 7836            .tasks
 7837            .iter()
 7838            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7839
 7840        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7841        let tasks = Arc::new(tasks.to_owned());
 7842        Some((buffer, *row, tasks))
 7843    }
 7844
 7845    fn find_enclosing_node_task(
 7846        &mut self,
 7847        cx: &mut Context<Self>,
 7848    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7849        let snapshot = self.buffer.read(cx).snapshot(cx);
 7850        let offset = self.selections.newest::<usize>(cx).head();
 7851        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7852        let buffer_id = excerpt.buffer().remote_id();
 7853
 7854        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7855        let mut cursor = layer.node().walk();
 7856
 7857        while cursor.goto_first_child_for_byte(offset).is_some() {
 7858            if cursor.node().end_byte() == offset {
 7859                cursor.goto_next_sibling();
 7860            }
 7861        }
 7862
 7863        // Ascend to the smallest ancestor that contains the range and has a task.
 7864        loop {
 7865            let node = cursor.node();
 7866            let node_range = node.byte_range();
 7867            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7868
 7869            // Check if this node contains our offset
 7870            if node_range.start <= offset && node_range.end >= offset {
 7871                // If it contains offset, check for task
 7872                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7873                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7874                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7875                }
 7876            }
 7877
 7878            if !cursor.goto_parent() {
 7879                break;
 7880            }
 7881        }
 7882        None
 7883    }
 7884
 7885    fn render_run_indicator(
 7886        &self,
 7887        _style: &EditorStyle,
 7888        is_active: bool,
 7889        row: DisplayRow,
 7890        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7891        cx: &mut Context<Self>,
 7892    ) -> IconButton {
 7893        let color = Color::Muted;
 7894        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7895
 7896        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7897            .shape(ui::IconButtonShape::Square)
 7898            .icon_size(IconSize::XSmall)
 7899            .icon_color(color)
 7900            .toggle_state(is_active)
 7901            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7902                let quick_launch = e.down.button == MouseButton::Left;
 7903                window.focus(&editor.focus_handle(cx));
 7904                editor.toggle_code_actions(
 7905                    &ToggleCodeActions {
 7906                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7907                        quick_launch,
 7908                    },
 7909                    window,
 7910                    cx,
 7911                );
 7912            }))
 7913            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7914                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7915            }))
 7916    }
 7917
 7918    pub fn context_menu_visible(&self) -> bool {
 7919        !self.edit_prediction_preview_is_active()
 7920            && self
 7921                .context_menu
 7922                .borrow()
 7923                .as_ref()
 7924                .map_or(false, |menu| menu.visible())
 7925    }
 7926
 7927    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7928        self.context_menu
 7929            .borrow()
 7930            .as_ref()
 7931            .map(|menu| menu.origin())
 7932    }
 7933
 7934    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7935        self.context_menu_options = Some(options);
 7936    }
 7937
 7938    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7939    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7940
 7941    fn render_edit_prediction_popover(
 7942        &mut self,
 7943        text_bounds: &Bounds<Pixels>,
 7944        content_origin: gpui::Point<Pixels>,
 7945        right_margin: Pixels,
 7946        editor_snapshot: &EditorSnapshot,
 7947        visible_row_range: Range<DisplayRow>,
 7948        scroll_top: f32,
 7949        scroll_bottom: f32,
 7950        line_layouts: &[LineWithInvisibles],
 7951        line_height: Pixels,
 7952        scroll_pixel_position: gpui::Point<Pixels>,
 7953        newest_selection_head: Option<DisplayPoint>,
 7954        editor_width: Pixels,
 7955        style: &EditorStyle,
 7956        window: &mut Window,
 7957        cx: &mut App,
 7958    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7959        if self.mode().is_minimap() {
 7960            return None;
 7961        }
 7962        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7963
 7964        if self.edit_prediction_visible_in_cursor_popover(true) {
 7965            return None;
 7966        }
 7967
 7968        match &active_inline_completion.completion {
 7969            InlineCompletion::Move { target, .. } => {
 7970                let target_display_point = target.to_display_point(editor_snapshot);
 7971
 7972                if self.edit_prediction_requires_modifier() {
 7973                    if !self.edit_prediction_preview_is_active() {
 7974                        return None;
 7975                    }
 7976
 7977                    self.render_edit_prediction_modifier_jump_popover(
 7978                        text_bounds,
 7979                        content_origin,
 7980                        visible_row_range,
 7981                        line_layouts,
 7982                        line_height,
 7983                        scroll_pixel_position,
 7984                        newest_selection_head,
 7985                        target_display_point,
 7986                        window,
 7987                        cx,
 7988                    )
 7989                } else {
 7990                    self.render_edit_prediction_eager_jump_popover(
 7991                        text_bounds,
 7992                        content_origin,
 7993                        editor_snapshot,
 7994                        visible_row_range,
 7995                        scroll_top,
 7996                        scroll_bottom,
 7997                        line_height,
 7998                        scroll_pixel_position,
 7999                        target_display_point,
 8000                        editor_width,
 8001                        window,
 8002                        cx,
 8003                    )
 8004                }
 8005            }
 8006            InlineCompletion::Edit {
 8007                display_mode: EditDisplayMode::Inline,
 8008                ..
 8009            } => None,
 8010            InlineCompletion::Edit {
 8011                display_mode: EditDisplayMode::TabAccept,
 8012                edits,
 8013                ..
 8014            } => {
 8015                let range = &edits.first()?.0;
 8016                let target_display_point = range.end.to_display_point(editor_snapshot);
 8017
 8018                self.render_edit_prediction_end_of_line_popover(
 8019                    "Accept",
 8020                    editor_snapshot,
 8021                    visible_row_range,
 8022                    target_display_point,
 8023                    line_height,
 8024                    scroll_pixel_position,
 8025                    content_origin,
 8026                    editor_width,
 8027                    window,
 8028                    cx,
 8029                )
 8030            }
 8031            InlineCompletion::Edit {
 8032                edits,
 8033                edit_preview,
 8034                display_mode: EditDisplayMode::DiffPopover,
 8035                snapshot,
 8036            } => self.render_edit_prediction_diff_popover(
 8037                text_bounds,
 8038                content_origin,
 8039                right_margin,
 8040                editor_snapshot,
 8041                visible_row_range,
 8042                line_layouts,
 8043                line_height,
 8044                scroll_pixel_position,
 8045                newest_selection_head,
 8046                editor_width,
 8047                style,
 8048                edits,
 8049                edit_preview,
 8050                snapshot,
 8051                window,
 8052                cx,
 8053            ),
 8054        }
 8055    }
 8056
 8057    fn render_edit_prediction_modifier_jump_popover(
 8058        &mut self,
 8059        text_bounds: &Bounds<Pixels>,
 8060        content_origin: gpui::Point<Pixels>,
 8061        visible_row_range: Range<DisplayRow>,
 8062        line_layouts: &[LineWithInvisibles],
 8063        line_height: Pixels,
 8064        scroll_pixel_position: gpui::Point<Pixels>,
 8065        newest_selection_head: Option<DisplayPoint>,
 8066        target_display_point: DisplayPoint,
 8067        window: &mut Window,
 8068        cx: &mut App,
 8069    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8070        let scrolled_content_origin =
 8071            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8072
 8073        const SCROLL_PADDING_Y: Pixels = px(12.);
 8074
 8075        if target_display_point.row() < visible_row_range.start {
 8076            return self.render_edit_prediction_scroll_popover(
 8077                |_| SCROLL_PADDING_Y,
 8078                IconName::ArrowUp,
 8079                visible_row_range,
 8080                line_layouts,
 8081                newest_selection_head,
 8082                scrolled_content_origin,
 8083                window,
 8084                cx,
 8085            );
 8086        } else if target_display_point.row() >= visible_row_range.end {
 8087            return self.render_edit_prediction_scroll_popover(
 8088                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8089                IconName::ArrowDown,
 8090                visible_row_range,
 8091                line_layouts,
 8092                newest_selection_head,
 8093                scrolled_content_origin,
 8094                window,
 8095                cx,
 8096            );
 8097        }
 8098
 8099        const POLE_WIDTH: Pixels = px(2.);
 8100
 8101        let line_layout =
 8102            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8103        let target_column = target_display_point.column() as usize;
 8104
 8105        let target_x = line_layout.x_for_index(target_column);
 8106        let target_y =
 8107            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8108
 8109        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8110
 8111        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8112        border_color.l += 0.001;
 8113
 8114        let mut element = v_flex()
 8115            .items_end()
 8116            .when(flag_on_right, |el| el.items_start())
 8117            .child(if flag_on_right {
 8118                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8119                    .rounded_bl(px(0.))
 8120                    .rounded_tl(px(0.))
 8121                    .border_l_2()
 8122                    .border_color(border_color)
 8123            } else {
 8124                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8125                    .rounded_br(px(0.))
 8126                    .rounded_tr(px(0.))
 8127                    .border_r_2()
 8128                    .border_color(border_color)
 8129            })
 8130            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8131            .into_any();
 8132
 8133        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8134
 8135        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8136            - point(
 8137                if flag_on_right {
 8138                    POLE_WIDTH
 8139                } else {
 8140                    size.width - POLE_WIDTH
 8141                },
 8142                size.height - line_height,
 8143            );
 8144
 8145        origin.x = origin.x.max(content_origin.x);
 8146
 8147        element.prepaint_at(origin, window, cx);
 8148
 8149        Some((element, origin))
 8150    }
 8151
 8152    fn render_edit_prediction_scroll_popover(
 8153        &mut self,
 8154        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8155        scroll_icon: IconName,
 8156        visible_row_range: Range<DisplayRow>,
 8157        line_layouts: &[LineWithInvisibles],
 8158        newest_selection_head: Option<DisplayPoint>,
 8159        scrolled_content_origin: gpui::Point<Pixels>,
 8160        window: &mut Window,
 8161        cx: &mut App,
 8162    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8163        let mut element = self
 8164            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8165            .into_any();
 8166
 8167        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8168
 8169        let cursor = newest_selection_head?;
 8170        let cursor_row_layout =
 8171            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8172        let cursor_column = cursor.column() as usize;
 8173
 8174        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8175
 8176        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8177
 8178        element.prepaint_at(origin, window, cx);
 8179        Some((element, origin))
 8180    }
 8181
 8182    fn render_edit_prediction_eager_jump_popover(
 8183        &mut self,
 8184        text_bounds: &Bounds<Pixels>,
 8185        content_origin: gpui::Point<Pixels>,
 8186        editor_snapshot: &EditorSnapshot,
 8187        visible_row_range: Range<DisplayRow>,
 8188        scroll_top: f32,
 8189        scroll_bottom: f32,
 8190        line_height: Pixels,
 8191        scroll_pixel_position: gpui::Point<Pixels>,
 8192        target_display_point: DisplayPoint,
 8193        editor_width: Pixels,
 8194        window: &mut Window,
 8195        cx: &mut App,
 8196    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8197        if target_display_point.row().as_f32() < scroll_top {
 8198            let mut element = self
 8199                .render_edit_prediction_line_popover(
 8200                    "Jump to Edit",
 8201                    Some(IconName::ArrowUp),
 8202                    window,
 8203                    cx,
 8204                )?
 8205                .into_any();
 8206
 8207            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8208            let offset = point(
 8209                (text_bounds.size.width - size.width) / 2.,
 8210                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8211            );
 8212
 8213            let origin = text_bounds.origin + offset;
 8214            element.prepaint_at(origin, window, cx);
 8215            Some((element, origin))
 8216        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8217            let mut element = self
 8218                .render_edit_prediction_line_popover(
 8219                    "Jump to Edit",
 8220                    Some(IconName::ArrowDown),
 8221                    window,
 8222                    cx,
 8223                )?
 8224                .into_any();
 8225
 8226            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8227            let offset = point(
 8228                (text_bounds.size.width - size.width) / 2.,
 8229                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8230            );
 8231
 8232            let origin = text_bounds.origin + offset;
 8233            element.prepaint_at(origin, window, cx);
 8234            Some((element, origin))
 8235        } else {
 8236            self.render_edit_prediction_end_of_line_popover(
 8237                "Jump to Edit",
 8238                editor_snapshot,
 8239                visible_row_range,
 8240                target_display_point,
 8241                line_height,
 8242                scroll_pixel_position,
 8243                content_origin,
 8244                editor_width,
 8245                window,
 8246                cx,
 8247            )
 8248        }
 8249    }
 8250
 8251    fn render_edit_prediction_end_of_line_popover(
 8252        self: &mut Editor,
 8253        label: &'static str,
 8254        editor_snapshot: &EditorSnapshot,
 8255        visible_row_range: Range<DisplayRow>,
 8256        target_display_point: DisplayPoint,
 8257        line_height: Pixels,
 8258        scroll_pixel_position: gpui::Point<Pixels>,
 8259        content_origin: gpui::Point<Pixels>,
 8260        editor_width: Pixels,
 8261        window: &mut Window,
 8262        cx: &mut App,
 8263    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8264        let target_line_end = DisplayPoint::new(
 8265            target_display_point.row(),
 8266            editor_snapshot.line_len(target_display_point.row()),
 8267        );
 8268
 8269        let mut element = self
 8270            .render_edit_prediction_line_popover(label, None, window, cx)?
 8271            .into_any();
 8272
 8273        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8274
 8275        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8276
 8277        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8278        let mut origin = start_point
 8279            + line_origin
 8280            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8281        origin.x = origin.x.max(content_origin.x);
 8282
 8283        let max_x = content_origin.x + editor_width - size.width;
 8284
 8285        if origin.x > max_x {
 8286            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8287
 8288            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8289                origin.y += offset;
 8290                IconName::ArrowUp
 8291            } else {
 8292                origin.y -= offset;
 8293                IconName::ArrowDown
 8294            };
 8295
 8296            element = self
 8297                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8298                .into_any();
 8299
 8300            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8301
 8302            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8303        }
 8304
 8305        element.prepaint_at(origin, window, cx);
 8306        Some((element, origin))
 8307    }
 8308
 8309    fn render_edit_prediction_diff_popover(
 8310        self: &Editor,
 8311        text_bounds: &Bounds<Pixels>,
 8312        content_origin: gpui::Point<Pixels>,
 8313        right_margin: Pixels,
 8314        editor_snapshot: &EditorSnapshot,
 8315        visible_row_range: Range<DisplayRow>,
 8316        line_layouts: &[LineWithInvisibles],
 8317        line_height: Pixels,
 8318        scroll_pixel_position: gpui::Point<Pixels>,
 8319        newest_selection_head: Option<DisplayPoint>,
 8320        editor_width: Pixels,
 8321        style: &EditorStyle,
 8322        edits: &Vec<(Range<Anchor>, String)>,
 8323        edit_preview: &Option<language::EditPreview>,
 8324        snapshot: &language::BufferSnapshot,
 8325        window: &mut Window,
 8326        cx: &mut App,
 8327    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8328        let edit_start = edits
 8329            .first()
 8330            .unwrap()
 8331            .0
 8332            .start
 8333            .to_display_point(editor_snapshot);
 8334        let edit_end = edits
 8335            .last()
 8336            .unwrap()
 8337            .0
 8338            .end
 8339            .to_display_point(editor_snapshot);
 8340
 8341        let is_visible = visible_row_range.contains(&edit_start.row())
 8342            || visible_row_range.contains(&edit_end.row());
 8343        if !is_visible {
 8344            return None;
 8345        }
 8346
 8347        let highlighted_edits =
 8348            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8349
 8350        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8351        let line_count = highlighted_edits.text.lines().count();
 8352
 8353        const BORDER_WIDTH: Pixels = px(1.);
 8354
 8355        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8356        let has_keybind = keybind.is_some();
 8357
 8358        let mut element = h_flex()
 8359            .items_start()
 8360            .child(
 8361                h_flex()
 8362                    .bg(cx.theme().colors().editor_background)
 8363                    .border(BORDER_WIDTH)
 8364                    .shadow_sm()
 8365                    .border_color(cx.theme().colors().border)
 8366                    .rounded_l_lg()
 8367                    .when(line_count > 1, |el| el.rounded_br_lg())
 8368                    .pr_1()
 8369                    .child(styled_text),
 8370            )
 8371            .child(
 8372                h_flex()
 8373                    .h(line_height + BORDER_WIDTH * 2.)
 8374                    .px_1p5()
 8375                    .gap_1()
 8376                    // Workaround: For some reason, there's a gap if we don't do this
 8377                    .ml(-BORDER_WIDTH)
 8378                    .shadow(vec![gpui::BoxShadow {
 8379                        color: gpui::black().opacity(0.05),
 8380                        offset: point(px(1.), px(1.)),
 8381                        blur_radius: px(2.),
 8382                        spread_radius: px(0.),
 8383                    }])
 8384                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8385                    .border(BORDER_WIDTH)
 8386                    .border_color(cx.theme().colors().border)
 8387                    .rounded_r_lg()
 8388                    .id("edit_prediction_diff_popover_keybind")
 8389                    .when(!has_keybind, |el| {
 8390                        let status_colors = cx.theme().status();
 8391
 8392                        el.bg(status_colors.error_background)
 8393                            .border_color(status_colors.error.opacity(0.6))
 8394                            .child(Icon::new(IconName::Info).color(Color::Error))
 8395                            .cursor_default()
 8396                            .hoverable_tooltip(move |_window, cx| {
 8397                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8398                            })
 8399                    })
 8400                    .children(keybind),
 8401            )
 8402            .into_any();
 8403
 8404        let longest_row =
 8405            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8406        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8407            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8408        } else {
 8409            layout_line(
 8410                longest_row,
 8411                editor_snapshot,
 8412                style,
 8413                editor_width,
 8414                |_| false,
 8415                window,
 8416                cx,
 8417            )
 8418            .width
 8419        };
 8420
 8421        let viewport_bounds =
 8422            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8423                right: -right_margin,
 8424                ..Default::default()
 8425            });
 8426
 8427        let x_after_longest =
 8428            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8429                - scroll_pixel_position.x;
 8430
 8431        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8432
 8433        // Fully visible if it can be displayed within the window (allow overlapping other
 8434        // panes). However, this is only allowed if the popover starts within text_bounds.
 8435        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8436            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8437
 8438        let mut origin = if can_position_to_the_right {
 8439            point(
 8440                x_after_longest,
 8441                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8442                    - scroll_pixel_position.y,
 8443            )
 8444        } else {
 8445            let cursor_row = newest_selection_head.map(|head| head.row());
 8446            let above_edit = edit_start
 8447                .row()
 8448                .0
 8449                .checked_sub(line_count as u32)
 8450                .map(DisplayRow);
 8451            let below_edit = Some(edit_end.row() + 1);
 8452            let above_cursor =
 8453                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8454            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8455
 8456            // Place the edit popover adjacent to the edit if there is a location
 8457            // available that is onscreen and does not obscure the cursor. Otherwise,
 8458            // place it adjacent to the cursor.
 8459            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8460                .into_iter()
 8461                .flatten()
 8462                .find(|&start_row| {
 8463                    let end_row = start_row + line_count as u32;
 8464                    visible_row_range.contains(&start_row)
 8465                        && visible_row_range.contains(&end_row)
 8466                        && cursor_row.map_or(true, |cursor_row| {
 8467                            !((start_row..end_row).contains(&cursor_row))
 8468                        })
 8469                })?;
 8470
 8471            content_origin
 8472                + point(
 8473                    -scroll_pixel_position.x,
 8474                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8475                )
 8476        };
 8477
 8478        origin.x -= BORDER_WIDTH;
 8479
 8480        window.defer_draw(element, origin, 1);
 8481
 8482        // Do not return an element, since it will already be drawn due to defer_draw.
 8483        None
 8484    }
 8485
 8486    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8487        px(30.)
 8488    }
 8489
 8490    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8491        if self.read_only(cx) {
 8492            cx.theme().players().read_only()
 8493        } else {
 8494            self.style.as_ref().unwrap().local_player
 8495        }
 8496    }
 8497
 8498    fn render_edit_prediction_accept_keybind(
 8499        &self,
 8500        window: &mut Window,
 8501        cx: &App,
 8502    ) -> Option<AnyElement> {
 8503        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8504        let accept_keystroke = accept_binding.keystroke()?;
 8505
 8506        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8507
 8508        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8509            Color::Accent
 8510        } else {
 8511            Color::Muted
 8512        };
 8513
 8514        h_flex()
 8515            .px_0p5()
 8516            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8517            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8518            .text_size(TextSize::XSmall.rems(cx))
 8519            .child(h_flex().children(ui::render_modifiers(
 8520                &accept_keystroke.modifiers,
 8521                PlatformStyle::platform(),
 8522                Some(modifiers_color),
 8523                Some(IconSize::XSmall.rems().into()),
 8524                true,
 8525            )))
 8526            .when(is_platform_style_mac, |parent| {
 8527                parent.child(accept_keystroke.key.clone())
 8528            })
 8529            .when(!is_platform_style_mac, |parent| {
 8530                parent.child(
 8531                    Key::new(
 8532                        util::capitalize(&accept_keystroke.key),
 8533                        Some(Color::Default),
 8534                    )
 8535                    .size(Some(IconSize::XSmall.rems().into())),
 8536                )
 8537            })
 8538            .into_any()
 8539            .into()
 8540    }
 8541
 8542    fn render_edit_prediction_line_popover(
 8543        &self,
 8544        label: impl Into<SharedString>,
 8545        icon: Option<IconName>,
 8546        window: &mut Window,
 8547        cx: &App,
 8548    ) -> Option<Stateful<Div>> {
 8549        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8550
 8551        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8552        let has_keybind = keybind.is_some();
 8553
 8554        let result = h_flex()
 8555            .id("ep-line-popover")
 8556            .py_0p5()
 8557            .pl_1()
 8558            .pr(padding_right)
 8559            .gap_1()
 8560            .rounded_md()
 8561            .border_1()
 8562            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8563            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8564            .shadow_sm()
 8565            .when(!has_keybind, |el| {
 8566                let status_colors = cx.theme().status();
 8567
 8568                el.bg(status_colors.error_background)
 8569                    .border_color(status_colors.error.opacity(0.6))
 8570                    .pl_2()
 8571                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8572                    .cursor_default()
 8573                    .hoverable_tooltip(move |_window, cx| {
 8574                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8575                    })
 8576            })
 8577            .children(keybind)
 8578            .child(
 8579                Label::new(label)
 8580                    .size(LabelSize::Small)
 8581                    .when(!has_keybind, |el| {
 8582                        el.color(cx.theme().status().error.into()).strikethrough()
 8583                    }),
 8584            )
 8585            .when(!has_keybind, |el| {
 8586                el.child(
 8587                    h_flex().ml_1().child(
 8588                        Icon::new(IconName::Info)
 8589                            .size(IconSize::Small)
 8590                            .color(cx.theme().status().error.into()),
 8591                    ),
 8592                )
 8593            })
 8594            .when_some(icon, |element, icon| {
 8595                element.child(
 8596                    div()
 8597                        .mt(px(1.5))
 8598                        .child(Icon::new(icon).size(IconSize::Small)),
 8599                )
 8600            });
 8601
 8602        Some(result)
 8603    }
 8604
 8605    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8606        let accent_color = cx.theme().colors().text_accent;
 8607        let editor_bg_color = cx.theme().colors().editor_background;
 8608        editor_bg_color.blend(accent_color.opacity(0.1))
 8609    }
 8610
 8611    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8612        let accent_color = cx.theme().colors().text_accent;
 8613        let editor_bg_color = cx.theme().colors().editor_background;
 8614        editor_bg_color.blend(accent_color.opacity(0.6))
 8615    }
 8616
 8617    fn render_edit_prediction_cursor_popover(
 8618        &self,
 8619        min_width: Pixels,
 8620        max_width: Pixels,
 8621        cursor_point: Point,
 8622        style: &EditorStyle,
 8623        accept_keystroke: Option<&gpui::Keystroke>,
 8624        _window: &Window,
 8625        cx: &mut Context<Editor>,
 8626    ) -> Option<AnyElement> {
 8627        let provider = self.edit_prediction_provider.as_ref()?;
 8628
 8629        if provider.provider.needs_terms_acceptance(cx) {
 8630            return Some(
 8631                h_flex()
 8632                    .min_w(min_width)
 8633                    .flex_1()
 8634                    .px_2()
 8635                    .py_1()
 8636                    .gap_3()
 8637                    .elevation_2(cx)
 8638                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8639                    .id("accept-terms")
 8640                    .cursor_pointer()
 8641                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8642                    .on_click(cx.listener(|this, _event, window, cx| {
 8643                        cx.stop_propagation();
 8644                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8645                        window.dispatch_action(
 8646                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8647                            cx,
 8648                        );
 8649                    }))
 8650                    .child(
 8651                        h_flex()
 8652                            .flex_1()
 8653                            .gap_2()
 8654                            .child(Icon::new(IconName::ZedPredict))
 8655                            .child(Label::new("Accept Terms of Service"))
 8656                            .child(div().w_full())
 8657                            .child(
 8658                                Icon::new(IconName::ArrowUpRight)
 8659                                    .color(Color::Muted)
 8660                                    .size(IconSize::Small),
 8661                            )
 8662                            .into_any_element(),
 8663                    )
 8664                    .into_any(),
 8665            );
 8666        }
 8667
 8668        let is_refreshing = provider.provider.is_refreshing(cx);
 8669
 8670        fn pending_completion_container() -> Div {
 8671            h_flex()
 8672                .h_full()
 8673                .flex_1()
 8674                .gap_2()
 8675                .child(Icon::new(IconName::ZedPredict))
 8676        }
 8677
 8678        let completion = match &self.active_inline_completion {
 8679            Some(prediction) => {
 8680                if !self.has_visible_completions_menu() {
 8681                    const RADIUS: Pixels = px(6.);
 8682                    const BORDER_WIDTH: Pixels = px(1.);
 8683
 8684                    return Some(
 8685                        h_flex()
 8686                            .elevation_2(cx)
 8687                            .border(BORDER_WIDTH)
 8688                            .border_color(cx.theme().colors().border)
 8689                            .when(accept_keystroke.is_none(), |el| {
 8690                                el.border_color(cx.theme().status().error)
 8691                            })
 8692                            .rounded(RADIUS)
 8693                            .rounded_tl(px(0.))
 8694                            .overflow_hidden()
 8695                            .child(div().px_1p5().child(match &prediction.completion {
 8696                                InlineCompletion::Move { target, snapshot } => {
 8697                                    use text::ToPoint as _;
 8698                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8699                                    {
 8700                                        Icon::new(IconName::ZedPredictDown)
 8701                                    } else {
 8702                                        Icon::new(IconName::ZedPredictUp)
 8703                                    }
 8704                                }
 8705                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8706                            }))
 8707                            .child(
 8708                                h_flex()
 8709                                    .gap_1()
 8710                                    .py_1()
 8711                                    .px_2()
 8712                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8713                                    .border_l_1()
 8714                                    .border_color(cx.theme().colors().border)
 8715                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8716                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8717                                        el.child(
 8718                                            Label::new("Hold")
 8719                                                .size(LabelSize::Small)
 8720                                                .when(accept_keystroke.is_none(), |el| {
 8721                                                    el.strikethrough()
 8722                                                })
 8723                                                .line_height_style(LineHeightStyle::UiLabel),
 8724                                        )
 8725                                    })
 8726                                    .id("edit_prediction_cursor_popover_keybind")
 8727                                    .when(accept_keystroke.is_none(), |el| {
 8728                                        let status_colors = cx.theme().status();
 8729
 8730                                        el.bg(status_colors.error_background)
 8731                                            .border_color(status_colors.error.opacity(0.6))
 8732                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8733                                            .cursor_default()
 8734                                            .hoverable_tooltip(move |_window, cx| {
 8735                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8736                                                    .into()
 8737                                            })
 8738                                    })
 8739                                    .when_some(
 8740                                        accept_keystroke.as_ref(),
 8741                                        |el, accept_keystroke| {
 8742                                            el.child(h_flex().children(ui::render_modifiers(
 8743                                                &accept_keystroke.modifiers,
 8744                                                PlatformStyle::platform(),
 8745                                                Some(Color::Default),
 8746                                                Some(IconSize::XSmall.rems().into()),
 8747                                                false,
 8748                                            )))
 8749                                        },
 8750                                    ),
 8751                            )
 8752                            .into_any(),
 8753                    );
 8754                }
 8755
 8756                self.render_edit_prediction_cursor_popover_preview(
 8757                    prediction,
 8758                    cursor_point,
 8759                    style,
 8760                    cx,
 8761                )?
 8762            }
 8763
 8764            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8765                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8766                    stale_completion,
 8767                    cursor_point,
 8768                    style,
 8769                    cx,
 8770                )?,
 8771
 8772                None => {
 8773                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8774                }
 8775            },
 8776
 8777            None => pending_completion_container().child(Label::new("No Prediction")),
 8778        };
 8779
 8780        let completion = if is_refreshing {
 8781            completion
 8782                .with_animation(
 8783                    "loading-completion",
 8784                    Animation::new(Duration::from_secs(2))
 8785                        .repeat()
 8786                        .with_easing(pulsating_between(0.4, 0.8)),
 8787                    |label, delta| label.opacity(delta),
 8788                )
 8789                .into_any_element()
 8790        } else {
 8791            completion.into_any_element()
 8792        };
 8793
 8794        let has_completion = self.active_inline_completion.is_some();
 8795
 8796        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8797        Some(
 8798            h_flex()
 8799                .min_w(min_width)
 8800                .max_w(max_width)
 8801                .flex_1()
 8802                .elevation_2(cx)
 8803                .border_color(cx.theme().colors().border)
 8804                .child(
 8805                    div()
 8806                        .flex_1()
 8807                        .py_1()
 8808                        .px_2()
 8809                        .overflow_hidden()
 8810                        .child(completion),
 8811                )
 8812                .when_some(accept_keystroke, |el, accept_keystroke| {
 8813                    if !accept_keystroke.modifiers.modified() {
 8814                        return el;
 8815                    }
 8816
 8817                    el.child(
 8818                        h_flex()
 8819                            .h_full()
 8820                            .border_l_1()
 8821                            .rounded_r_lg()
 8822                            .border_color(cx.theme().colors().border)
 8823                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8824                            .gap_1()
 8825                            .py_1()
 8826                            .px_2()
 8827                            .child(
 8828                                h_flex()
 8829                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8830                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8831                                    .child(h_flex().children(ui::render_modifiers(
 8832                                        &accept_keystroke.modifiers,
 8833                                        PlatformStyle::platform(),
 8834                                        Some(if !has_completion {
 8835                                            Color::Muted
 8836                                        } else {
 8837                                            Color::Default
 8838                                        }),
 8839                                        None,
 8840                                        false,
 8841                                    ))),
 8842                            )
 8843                            .child(Label::new("Preview").into_any_element())
 8844                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8845                    )
 8846                })
 8847                .into_any(),
 8848        )
 8849    }
 8850
 8851    fn render_edit_prediction_cursor_popover_preview(
 8852        &self,
 8853        completion: &InlineCompletionState,
 8854        cursor_point: Point,
 8855        style: &EditorStyle,
 8856        cx: &mut Context<Editor>,
 8857    ) -> Option<Div> {
 8858        use text::ToPoint as _;
 8859
 8860        fn render_relative_row_jump(
 8861            prefix: impl Into<String>,
 8862            current_row: u32,
 8863            target_row: u32,
 8864        ) -> Div {
 8865            let (row_diff, arrow) = if target_row < current_row {
 8866                (current_row - target_row, IconName::ArrowUp)
 8867            } else {
 8868                (target_row - current_row, IconName::ArrowDown)
 8869            };
 8870
 8871            h_flex()
 8872                .child(
 8873                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8874                        .color(Color::Muted)
 8875                        .size(LabelSize::Small),
 8876                )
 8877                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8878        }
 8879
 8880        match &completion.completion {
 8881            InlineCompletion::Move {
 8882                target, snapshot, ..
 8883            } => Some(
 8884                h_flex()
 8885                    .px_2()
 8886                    .gap_2()
 8887                    .flex_1()
 8888                    .child(
 8889                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8890                            Icon::new(IconName::ZedPredictDown)
 8891                        } else {
 8892                            Icon::new(IconName::ZedPredictUp)
 8893                        },
 8894                    )
 8895                    .child(Label::new("Jump to Edit")),
 8896            ),
 8897
 8898            InlineCompletion::Edit {
 8899                edits,
 8900                edit_preview,
 8901                snapshot,
 8902                display_mode: _,
 8903            } => {
 8904                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8905
 8906                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8907                    &snapshot,
 8908                    &edits,
 8909                    edit_preview.as_ref()?,
 8910                    true,
 8911                    cx,
 8912                )
 8913                .first_line_preview();
 8914
 8915                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8916                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8917
 8918                let preview = h_flex()
 8919                    .gap_1()
 8920                    .min_w_16()
 8921                    .child(styled_text)
 8922                    .when(has_more_lines, |parent| parent.child(""));
 8923
 8924                let left = if first_edit_row != cursor_point.row {
 8925                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8926                        .into_any_element()
 8927                } else {
 8928                    Icon::new(IconName::ZedPredict).into_any_element()
 8929                };
 8930
 8931                Some(
 8932                    h_flex()
 8933                        .h_full()
 8934                        .flex_1()
 8935                        .gap_2()
 8936                        .pr_1()
 8937                        .overflow_x_hidden()
 8938                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8939                        .child(left)
 8940                        .child(preview),
 8941                )
 8942            }
 8943        }
 8944    }
 8945
 8946    pub fn render_context_menu(
 8947        &self,
 8948        style: &EditorStyle,
 8949        max_height_in_lines: u32,
 8950        window: &mut Window,
 8951        cx: &mut Context<Editor>,
 8952    ) -> Option<AnyElement> {
 8953        let menu = self.context_menu.borrow();
 8954        let menu = menu.as_ref()?;
 8955        if !menu.visible() {
 8956            return None;
 8957        };
 8958        Some(menu.render(style, max_height_in_lines, window, cx))
 8959    }
 8960
 8961    fn render_context_menu_aside(
 8962        &mut self,
 8963        max_size: Size<Pixels>,
 8964        window: &mut Window,
 8965        cx: &mut Context<Editor>,
 8966    ) -> Option<AnyElement> {
 8967        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8968            if menu.visible() {
 8969                menu.render_aside(max_size, window, cx)
 8970            } else {
 8971                None
 8972            }
 8973        })
 8974    }
 8975
 8976    fn hide_context_menu(
 8977        &mut self,
 8978        window: &mut Window,
 8979        cx: &mut Context<Self>,
 8980    ) -> Option<CodeContextMenu> {
 8981        cx.notify();
 8982        self.completion_tasks.clear();
 8983        let context_menu = self.context_menu.borrow_mut().take();
 8984        self.stale_inline_completion_in_menu.take();
 8985        self.update_visible_inline_completion(window, cx);
 8986        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8987            if let Some(completion_provider) = &self.completion_provider {
 8988                completion_provider.selection_changed(None, window, cx);
 8989            }
 8990        }
 8991        context_menu
 8992    }
 8993
 8994    fn show_snippet_choices(
 8995        &mut self,
 8996        choices: &Vec<String>,
 8997        selection: Range<Anchor>,
 8998        cx: &mut Context<Self>,
 8999    ) {
 9000        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9001            (Some(a), Some(b)) if a == b => a,
 9002            _ => {
 9003                log::error!("expected anchor range to have matching buffer IDs");
 9004                return;
 9005            }
 9006        };
 9007        let multi_buffer = self.buffer().read(cx);
 9008        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9009            return;
 9010        };
 9011
 9012        let id = post_inc(&mut self.next_completion_id);
 9013        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9014        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9015            CompletionsMenu::new_snippet_choices(
 9016                id,
 9017                true,
 9018                choices,
 9019                selection,
 9020                buffer,
 9021                snippet_sort_order,
 9022            ),
 9023        ));
 9024    }
 9025
 9026    pub fn insert_snippet(
 9027        &mut self,
 9028        insertion_ranges: &[Range<usize>],
 9029        snippet: Snippet,
 9030        window: &mut Window,
 9031        cx: &mut Context<Self>,
 9032    ) -> Result<()> {
 9033        struct Tabstop<T> {
 9034            is_end_tabstop: bool,
 9035            ranges: Vec<Range<T>>,
 9036            choices: Option<Vec<String>>,
 9037        }
 9038
 9039        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9040            let snippet_text: Arc<str> = snippet.text.clone().into();
 9041            let edits = insertion_ranges
 9042                .iter()
 9043                .cloned()
 9044                .map(|range| (range, snippet_text.clone()));
 9045            let autoindent_mode = AutoindentMode::Block {
 9046                original_indent_columns: Vec::new(),
 9047            };
 9048            buffer.edit(edits, Some(autoindent_mode), cx);
 9049
 9050            let snapshot = &*buffer.read(cx);
 9051            let snippet = &snippet;
 9052            snippet
 9053                .tabstops
 9054                .iter()
 9055                .map(|tabstop| {
 9056                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9057                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9058                    });
 9059                    let mut tabstop_ranges = tabstop
 9060                        .ranges
 9061                        .iter()
 9062                        .flat_map(|tabstop_range| {
 9063                            let mut delta = 0_isize;
 9064                            insertion_ranges.iter().map(move |insertion_range| {
 9065                                let insertion_start = insertion_range.start as isize + delta;
 9066                                delta +=
 9067                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9068
 9069                                let start = ((insertion_start + tabstop_range.start) as usize)
 9070                                    .min(snapshot.len());
 9071                                let end = ((insertion_start + tabstop_range.end) as usize)
 9072                                    .min(snapshot.len());
 9073                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9074                            })
 9075                        })
 9076                        .collect::<Vec<_>>();
 9077                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9078
 9079                    Tabstop {
 9080                        is_end_tabstop,
 9081                        ranges: tabstop_ranges,
 9082                        choices: tabstop.choices.clone(),
 9083                    }
 9084                })
 9085                .collect::<Vec<_>>()
 9086        });
 9087        if let Some(tabstop) = tabstops.first() {
 9088            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9089                // Reverse order so that the first range is the newest created selection.
 9090                // Completions will use it and autoscroll will prioritize it.
 9091                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9092            });
 9093
 9094            if let Some(choices) = &tabstop.choices {
 9095                if let Some(selection) = tabstop.ranges.first() {
 9096                    self.show_snippet_choices(choices, selection.clone(), cx)
 9097                }
 9098            }
 9099
 9100            // If we're already at the last tabstop and it's at the end of the snippet,
 9101            // we're done, we don't need to keep the state around.
 9102            if !tabstop.is_end_tabstop {
 9103                let choices = tabstops
 9104                    .iter()
 9105                    .map(|tabstop| tabstop.choices.clone())
 9106                    .collect();
 9107
 9108                let ranges = tabstops
 9109                    .into_iter()
 9110                    .map(|tabstop| tabstop.ranges)
 9111                    .collect::<Vec<_>>();
 9112
 9113                self.snippet_stack.push(SnippetState {
 9114                    active_index: 0,
 9115                    ranges,
 9116                    choices,
 9117                });
 9118            }
 9119
 9120            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9121            if self.autoclose_regions.is_empty() {
 9122                let snapshot = self.buffer.read(cx).snapshot(cx);
 9123                for selection in &mut self.selections.all::<Point>(cx) {
 9124                    let selection_head = selection.head();
 9125                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9126                        continue;
 9127                    };
 9128
 9129                    let mut bracket_pair = None;
 9130                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9131                    let prev_chars = snapshot
 9132                        .reversed_chars_at(selection_head)
 9133                        .collect::<String>();
 9134                    for (pair, enabled) in scope.brackets() {
 9135                        if enabled
 9136                            && pair.close
 9137                            && prev_chars.starts_with(pair.start.as_str())
 9138                            && next_chars.starts_with(pair.end.as_str())
 9139                        {
 9140                            bracket_pair = Some(pair.clone());
 9141                            break;
 9142                        }
 9143                    }
 9144                    if let Some(pair) = bracket_pair {
 9145                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9146                        let autoclose_enabled =
 9147                            self.use_autoclose && snapshot_settings.use_autoclose;
 9148                        if autoclose_enabled {
 9149                            let start = snapshot.anchor_after(selection_head);
 9150                            let end = snapshot.anchor_after(selection_head);
 9151                            self.autoclose_regions.push(AutocloseRegion {
 9152                                selection_id: selection.id,
 9153                                range: start..end,
 9154                                pair,
 9155                            });
 9156                        }
 9157                    }
 9158                }
 9159            }
 9160        }
 9161        Ok(())
 9162    }
 9163
 9164    pub fn move_to_next_snippet_tabstop(
 9165        &mut self,
 9166        window: &mut Window,
 9167        cx: &mut Context<Self>,
 9168    ) -> bool {
 9169        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9170    }
 9171
 9172    pub fn move_to_prev_snippet_tabstop(
 9173        &mut self,
 9174        window: &mut Window,
 9175        cx: &mut Context<Self>,
 9176    ) -> bool {
 9177        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9178    }
 9179
 9180    pub fn move_to_snippet_tabstop(
 9181        &mut self,
 9182        bias: Bias,
 9183        window: &mut Window,
 9184        cx: &mut Context<Self>,
 9185    ) -> bool {
 9186        if let Some(mut snippet) = self.snippet_stack.pop() {
 9187            match bias {
 9188                Bias::Left => {
 9189                    if snippet.active_index > 0 {
 9190                        snippet.active_index -= 1;
 9191                    } else {
 9192                        self.snippet_stack.push(snippet);
 9193                        return false;
 9194                    }
 9195                }
 9196                Bias::Right => {
 9197                    if snippet.active_index + 1 < snippet.ranges.len() {
 9198                        snippet.active_index += 1;
 9199                    } else {
 9200                        self.snippet_stack.push(snippet);
 9201                        return false;
 9202                    }
 9203                }
 9204            }
 9205            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9206                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9207                    // Reverse order so that the first range is the newest created selection.
 9208                    // Completions will use it and autoscroll will prioritize it.
 9209                    s.select_ranges(current_ranges.iter().rev().cloned())
 9210                });
 9211
 9212                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9213                    if let Some(selection) = current_ranges.first() {
 9214                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9215                    }
 9216                }
 9217
 9218                // If snippet state is not at the last tabstop, push it back on the stack
 9219                if snippet.active_index + 1 < snippet.ranges.len() {
 9220                    self.snippet_stack.push(snippet);
 9221                }
 9222                return true;
 9223            }
 9224        }
 9225
 9226        false
 9227    }
 9228
 9229    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9230        self.transact(window, cx, |this, window, cx| {
 9231            this.select_all(&SelectAll, window, cx);
 9232            this.insert("", window, cx);
 9233        });
 9234    }
 9235
 9236    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9237        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9238        self.transact(window, cx, |this, window, cx| {
 9239            this.select_autoclose_pair(window, cx);
 9240            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9241            if !this.linked_edit_ranges.is_empty() {
 9242                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9243                let snapshot = this.buffer.read(cx).snapshot(cx);
 9244
 9245                for selection in selections.iter() {
 9246                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9247                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9248                    if selection_start.buffer_id != selection_end.buffer_id {
 9249                        continue;
 9250                    }
 9251                    if let Some(ranges) =
 9252                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9253                    {
 9254                        for (buffer, entries) in ranges {
 9255                            linked_ranges.entry(buffer).or_default().extend(entries);
 9256                        }
 9257                    }
 9258                }
 9259            }
 9260
 9261            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9262            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9263            for selection in &mut selections {
 9264                if selection.is_empty() {
 9265                    let old_head = selection.head();
 9266                    let mut new_head =
 9267                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9268                            .to_point(&display_map);
 9269                    if let Some((buffer, line_buffer_range)) = display_map
 9270                        .buffer_snapshot
 9271                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9272                    {
 9273                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9274                        let indent_len = match indent_size.kind {
 9275                            IndentKind::Space => {
 9276                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9277                            }
 9278                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9279                        };
 9280                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9281                            let indent_len = indent_len.get();
 9282                            new_head = cmp::min(
 9283                                new_head,
 9284                                MultiBufferPoint::new(
 9285                                    old_head.row,
 9286                                    ((old_head.column - 1) / indent_len) * indent_len,
 9287                                ),
 9288                            );
 9289                        }
 9290                    }
 9291
 9292                    selection.set_head(new_head, SelectionGoal::None);
 9293                }
 9294            }
 9295
 9296            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9297                s.select(selections)
 9298            });
 9299            this.insert("", window, cx);
 9300            let empty_str: Arc<str> = Arc::from("");
 9301            for (buffer, edits) in linked_ranges {
 9302                let snapshot = buffer.read(cx).snapshot();
 9303                use text::ToPoint as TP;
 9304
 9305                let edits = edits
 9306                    .into_iter()
 9307                    .map(|range| {
 9308                        let end_point = TP::to_point(&range.end, &snapshot);
 9309                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9310
 9311                        if end_point == start_point {
 9312                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9313                                .saturating_sub(1);
 9314                            start_point =
 9315                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9316                        };
 9317
 9318                        (start_point..end_point, empty_str.clone())
 9319                    })
 9320                    .sorted_by_key(|(range, _)| range.start)
 9321                    .collect::<Vec<_>>();
 9322                buffer.update(cx, |this, cx| {
 9323                    this.edit(edits, None, cx);
 9324                })
 9325            }
 9326            this.refresh_inline_completion(true, false, window, cx);
 9327            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9328        });
 9329    }
 9330
 9331    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9332        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9333        self.transact(window, cx, |this, window, cx| {
 9334            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9335                s.move_with(|map, selection| {
 9336                    if selection.is_empty() {
 9337                        let cursor = movement::right(map, selection.head());
 9338                        selection.end = cursor;
 9339                        selection.reversed = true;
 9340                        selection.goal = SelectionGoal::None;
 9341                    }
 9342                })
 9343            });
 9344            this.insert("", window, cx);
 9345            this.refresh_inline_completion(true, false, window, cx);
 9346        });
 9347    }
 9348
 9349    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9350        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9351        if self.move_to_prev_snippet_tabstop(window, cx) {
 9352            return;
 9353        }
 9354        self.outdent(&Outdent, window, cx);
 9355    }
 9356
 9357    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9358        if self.move_to_next_snippet_tabstop(window, cx) {
 9359            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9360            return;
 9361        }
 9362        if self.read_only(cx) {
 9363            return;
 9364        }
 9365        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9366        let mut selections = self.selections.all_adjusted(cx);
 9367        let buffer = self.buffer.read(cx);
 9368        let snapshot = buffer.snapshot(cx);
 9369        let rows_iter = selections.iter().map(|s| s.head().row);
 9370        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9371
 9372        let has_some_cursor_in_whitespace = selections
 9373            .iter()
 9374            .filter(|selection| selection.is_empty())
 9375            .any(|selection| {
 9376                let cursor = selection.head();
 9377                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9378                cursor.column < current_indent.len
 9379            });
 9380
 9381        let mut edits = Vec::new();
 9382        let mut prev_edited_row = 0;
 9383        let mut row_delta = 0;
 9384        for selection in &mut selections {
 9385            if selection.start.row != prev_edited_row {
 9386                row_delta = 0;
 9387            }
 9388            prev_edited_row = selection.end.row;
 9389
 9390            // If the selection is non-empty, then increase the indentation of the selected lines.
 9391            if !selection.is_empty() {
 9392                row_delta =
 9393                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9394                continue;
 9395            }
 9396
 9397            let cursor = selection.head();
 9398            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9399            if let Some(suggested_indent) =
 9400                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9401            {
 9402                // Don't do anything if already at suggested indent
 9403                // and there is any other cursor which is not
 9404                if has_some_cursor_in_whitespace
 9405                    && cursor.column == current_indent.len
 9406                    && current_indent.len == suggested_indent.len
 9407                {
 9408                    continue;
 9409                }
 9410
 9411                // Adjust line and move cursor to suggested indent
 9412                // if cursor is not at suggested indent
 9413                if cursor.column < suggested_indent.len
 9414                    && cursor.column <= current_indent.len
 9415                    && current_indent.len <= suggested_indent.len
 9416                {
 9417                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9418                    selection.end = selection.start;
 9419                    if row_delta == 0 {
 9420                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9421                            cursor.row,
 9422                            current_indent,
 9423                            suggested_indent,
 9424                        ));
 9425                        row_delta = suggested_indent.len - current_indent.len;
 9426                    }
 9427                    continue;
 9428                }
 9429
 9430                // If current indent is more than suggested indent
 9431                // only move cursor to current indent and skip indent
 9432                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9433                    selection.start = Point::new(cursor.row, current_indent.len);
 9434                    selection.end = selection.start;
 9435                    continue;
 9436                }
 9437            }
 9438
 9439            // Otherwise, insert a hard or soft tab.
 9440            let settings = buffer.language_settings_at(cursor, cx);
 9441            let tab_size = if settings.hard_tabs {
 9442                IndentSize::tab()
 9443            } else {
 9444                let tab_size = settings.tab_size.get();
 9445                let indent_remainder = snapshot
 9446                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9447                    .flat_map(str::chars)
 9448                    .fold(row_delta % tab_size, |counter: u32, c| {
 9449                        if c == '\t' {
 9450                            0
 9451                        } else {
 9452                            (counter + 1) % tab_size
 9453                        }
 9454                    });
 9455
 9456                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9457                IndentSize::spaces(chars_to_next_tab_stop)
 9458            };
 9459            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9460            selection.end = selection.start;
 9461            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9462            row_delta += tab_size.len;
 9463        }
 9464
 9465        self.transact(window, cx, |this, window, cx| {
 9466            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9467            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9468                s.select(selections)
 9469            });
 9470            this.refresh_inline_completion(true, false, window, cx);
 9471        });
 9472    }
 9473
 9474    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9475        if self.read_only(cx) {
 9476            return;
 9477        }
 9478        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9479        let mut selections = self.selections.all::<Point>(cx);
 9480        let mut prev_edited_row = 0;
 9481        let mut row_delta = 0;
 9482        let mut edits = Vec::new();
 9483        let buffer = self.buffer.read(cx);
 9484        let snapshot = buffer.snapshot(cx);
 9485        for selection in &mut selections {
 9486            if selection.start.row != prev_edited_row {
 9487                row_delta = 0;
 9488            }
 9489            prev_edited_row = selection.end.row;
 9490
 9491            row_delta =
 9492                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9493        }
 9494
 9495        self.transact(window, cx, |this, window, cx| {
 9496            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9497            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9498                s.select(selections)
 9499            });
 9500        });
 9501    }
 9502
 9503    fn indent_selection(
 9504        buffer: &MultiBuffer,
 9505        snapshot: &MultiBufferSnapshot,
 9506        selection: &mut Selection<Point>,
 9507        edits: &mut Vec<(Range<Point>, String)>,
 9508        delta_for_start_row: u32,
 9509        cx: &App,
 9510    ) -> u32 {
 9511        let settings = buffer.language_settings_at(selection.start, cx);
 9512        let tab_size = settings.tab_size.get();
 9513        let indent_kind = if settings.hard_tabs {
 9514            IndentKind::Tab
 9515        } else {
 9516            IndentKind::Space
 9517        };
 9518        let mut start_row = selection.start.row;
 9519        let mut end_row = selection.end.row + 1;
 9520
 9521        // If a selection ends at the beginning of a line, don't indent
 9522        // that last line.
 9523        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9524            end_row -= 1;
 9525        }
 9526
 9527        // Avoid re-indenting a row that has already been indented by a
 9528        // previous selection, but still update this selection's column
 9529        // to reflect that indentation.
 9530        if delta_for_start_row > 0 {
 9531            start_row += 1;
 9532            selection.start.column += delta_for_start_row;
 9533            if selection.end.row == selection.start.row {
 9534                selection.end.column += delta_for_start_row;
 9535            }
 9536        }
 9537
 9538        let mut delta_for_end_row = 0;
 9539        let has_multiple_rows = start_row + 1 != end_row;
 9540        for row in start_row..end_row {
 9541            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9542            let indent_delta = match (current_indent.kind, indent_kind) {
 9543                (IndentKind::Space, IndentKind::Space) => {
 9544                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9545                    IndentSize::spaces(columns_to_next_tab_stop)
 9546                }
 9547                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9548                (_, IndentKind::Tab) => IndentSize::tab(),
 9549            };
 9550
 9551            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9552                0
 9553            } else {
 9554                selection.start.column
 9555            };
 9556            let row_start = Point::new(row, start);
 9557            edits.push((
 9558                row_start..row_start,
 9559                indent_delta.chars().collect::<String>(),
 9560            ));
 9561
 9562            // Update this selection's endpoints to reflect the indentation.
 9563            if row == selection.start.row {
 9564                selection.start.column += indent_delta.len;
 9565            }
 9566            if row == selection.end.row {
 9567                selection.end.column += indent_delta.len;
 9568                delta_for_end_row = indent_delta.len;
 9569            }
 9570        }
 9571
 9572        if selection.start.row == selection.end.row {
 9573            delta_for_start_row + delta_for_end_row
 9574        } else {
 9575            delta_for_end_row
 9576        }
 9577    }
 9578
 9579    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9580        if self.read_only(cx) {
 9581            return;
 9582        }
 9583        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9584        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9585        let selections = self.selections.all::<Point>(cx);
 9586        let mut deletion_ranges = Vec::new();
 9587        let mut last_outdent = None;
 9588        {
 9589            let buffer = self.buffer.read(cx);
 9590            let snapshot = buffer.snapshot(cx);
 9591            for selection in &selections {
 9592                let settings = buffer.language_settings_at(selection.start, cx);
 9593                let tab_size = settings.tab_size.get();
 9594                let mut rows = selection.spanned_rows(false, &display_map);
 9595
 9596                // Avoid re-outdenting a row that has already been outdented by a
 9597                // previous selection.
 9598                if let Some(last_row) = last_outdent {
 9599                    if last_row == rows.start {
 9600                        rows.start = rows.start.next_row();
 9601                    }
 9602                }
 9603                let has_multiple_rows = rows.len() > 1;
 9604                for row in rows.iter_rows() {
 9605                    let indent_size = snapshot.indent_size_for_line(row);
 9606                    if indent_size.len > 0 {
 9607                        let deletion_len = match indent_size.kind {
 9608                            IndentKind::Space => {
 9609                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9610                                if columns_to_prev_tab_stop == 0 {
 9611                                    tab_size
 9612                                } else {
 9613                                    columns_to_prev_tab_stop
 9614                                }
 9615                            }
 9616                            IndentKind::Tab => 1,
 9617                        };
 9618                        let start = if has_multiple_rows
 9619                            || deletion_len > selection.start.column
 9620                            || indent_size.len < selection.start.column
 9621                        {
 9622                            0
 9623                        } else {
 9624                            selection.start.column - deletion_len
 9625                        };
 9626                        deletion_ranges.push(
 9627                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9628                        );
 9629                        last_outdent = Some(row);
 9630                    }
 9631                }
 9632            }
 9633        }
 9634
 9635        self.transact(window, cx, |this, window, cx| {
 9636            this.buffer.update(cx, |buffer, cx| {
 9637                let empty_str: Arc<str> = Arc::default();
 9638                buffer.edit(
 9639                    deletion_ranges
 9640                        .into_iter()
 9641                        .map(|range| (range, empty_str.clone())),
 9642                    None,
 9643                    cx,
 9644                );
 9645            });
 9646            let selections = this.selections.all::<usize>(cx);
 9647            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9648                s.select(selections)
 9649            });
 9650        });
 9651    }
 9652
 9653    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9654        if self.read_only(cx) {
 9655            return;
 9656        }
 9657        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9658        let selections = self
 9659            .selections
 9660            .all::<usize>(cx)
 9661            .into_iter()
 9662            .map(|s| s.range());
 9663
 9664        self.transact(window, cx, |this, window, cx| {
 9665            this.buffer.update(cx, |buffer, cx| {
 9666                buffer.autoindent_ranges(selections, cx);
 9667            });
 9668            let selections = this.selections.all::<usize>(cx);
 9669            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9670                s.select(selections)
 9671            });
 9672        });
 9673    }
 9674
 9675    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9676        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9678        let selections = self.selections.all::<Point>(cx);
 9679
 9680        let mut new_cursors = Vec::new();
 9681        let mut edit_ranges = Vec::new();
 9682        let mut selections = selections.iter().peekable();
 9683        while let Some(selection) = selections.next() {
 9684            let mut rows = selection.spanned_rows(false, &display_map);
 9685            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9686
 9687            // Accumulate contiguous regions of rows that we want to delete.
 9688            while let Some(next_selection) = selections.peek() {
 9689                let next_rows = next_selection.spanned_rows(false, &display_map);
 9690                if next_rows.start <= rows.end {
 9691                    rows.end = next_rows.end;
 9692                    selections.next().unwrap();
 9693                } else {
 9694                    break;
 9695                }
 9696            }
 9697
 9698            let buffer = &display_map.buffer_snapshot;
 9699            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9700            let edit_end;
 9701            let cursor_buffer_row;
 9702            if buffer.max_point().row >= rows.end.0 {
 9703                // If there's a line after the range, delete the \n from the end of the row range
 9704                // and position the cursor on the next line.
 9705                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9706                cursor_buffer_row = rows.end;
 9707            } else {
 9708                // If there isn't a line after the range, delete the \n from the line before the
 9709                // start of the row range and position the cursor there.
 9710                edit_start = edit_start.saturating_sub(1);
 9711                edit_end = buffer.len();
 9712                cursor_buffer_row = rows.start.previous_row();
 9713            }
 9714
 9715            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9716            *cursor.column_mut() =
 9717                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9718
 9719            new_cursors.push((
 9720                selection.id,
 9721                buffer.anchor_after(cursor.to_point(&display_map)),
 9722            ));
 9723            edit_ranges.push(edit_start..edit_end);
 9724        }
 9725
 9726        self.transact(window, cx, |this, window, cx| {
 9727            let buffer = this.buffer.update(cx, |buffer, cx| {
 9728                let empty_str: Arc<str> = Arc::default();
 9729                buffer.edit(
 9730                    edit_ranges
 9731                        .into_iter()
 9732                        .map(|range| (range, empty_str.clone())),
 9733                    None,
 9734                    cx,
 9735                );
 9736                buffer.snapshot(cx)
 9737            });
 9738            let new_selections = new_cursors
 9739                .into_iter()
 9740                .map(|(id, cursor)| {
 9741                    let cursor = cursor.to_point(&buffer);
 9742                    Selection {
 9743                        id,
 9744                        start: cursor,
 9745                        end: cursor,
 9746                        reversed: false,
 9747                        goal: SelectionGoal::None,
 9748                    }
 9749                })
 9750                .collect();
 9751
 9752            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9753                s.select(new_selections);
 9754            });
 9755        });
 9756    }
 9757
 9758    pub fn join_lines_impl(
 9759        &mut self,
 9760        insert_whitespace: bool,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) {
 9764        if self.read_only(cx) {
 9765            return;
 9766        }
 9767        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9768        for selection in self.selections.all::<Point>(cx) {
 9769            let start = MultiBufferRow(selection.start.row);
 9770            // Treat single line selections as if they include the next line. Otherwise this action
 9771            // would do nothing for single line selections individual cursors.
 9772            let end = if selection.start.row == selection.end.row {
 9773                MultiBufferRow(selection.start.row + 1)
 9774            } else {
 9775                MultiBufferRow(selection.end.row)
 9776            };
 9777
 9778            if let Some(last_row_range) = row_ranges.last_mut() {
 9779                if start <= last_row_range.end {
 9780                    last_row_range.end = end;
 9781                    continue;
 9782                }
 9783            }
 9784            row_ranges.push(start..end);
 9785        }
 9786
 9787        let snapshot = self.buffer.read(cx).snapshot(cx);
 9788        let mut cursor_positions = Vec::new();
 9789        for row_range in &row_ranges {
 9790            let anchor = snapshot.anchor_before(Point::new(
 9791                row_range.end.previous_row().0,
 9792                snapshot.line_len(row_range.end.previous_row()),
 9793            ));
 9794            cursor_positions.push(anchor..anchor);
 9795        }
 9796
 9797        self.transact(window, cx, |this, window, cx| {
 9798            for row_range in row_ranges.into_iter().rev() {
 9799                for row in row_range.iter_rows().rev() {
 9800                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9801                    let next_line_row = row.next_row();
 9802                    let indent = snapshot.indent_size_for_line(next_line_row);
 9803                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9804
 9805                    let replace =
 9806                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9807                            " "
 9808                        } else {
 9809                            ""
 9810                        };
 9811
 9812                    this.buffer.update(cx, |buffer, cx| {
 9813                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9814                    });
 9815                }
 9816            }
 9817
 9818            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9819                s.select_anchor_ranges(cursor_positions)
 9820            });
 9821        });
 9822    }
 9823
 9824    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9825        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9826        self.join_lines_impl(true, window, cx);
 9827    }
 9828
 9829    pub fn sort_lines_case_sensitive(
 9830        &mut self,
 9831        _: &SortLinesCaseSensitive,
 9832        window: &mut Window,
 9833        cx: &mut Context<Self>,
 9834    ) {
 9835        self.manipulate_lines(window, cx, |lines| lines.sort())
 9836    }
 9837
 9838    pub fn sort_lines_case_insensitive(
 9839        &mut self,
 9840        _: &SortLinesCaseInsensitive,
 9841        window: &mut Window,
 9842        cx: &mut Context<Self>,
 9843    ) {
 9844        self.manipulate_lines(window, cx, |lines| {
 9845            lines.sort_by_key(|line| line.to_lowercase())
 9846        })
 9847    }
 9848
 9849    pub fn unique_lines_case_insensitive(
 9850        &mut self,
 9851        _: &UniqueLinesCaseInsensitive,
 9852        window: &mut Window,
 9853        cx: &mut Context<Self>,
 9854    ) {
 9855        self.manipulate_lines(window, cx, |lines| {
 9856            let mut seen = HashSet::default();
 9857            lines.retain(|line| seen.insert(line.to_lowercase()));
 9858        })
 9859    }
 9860
 9861    pub fn unique_lines_case_sensitive(
 9862        &mut self,
 9863        _: &UniqueLinesCaseSensitive,
 9864        window: &mut Window,
 9865        cx: &mut Context<Self>,
 9866    ) {
 9867        self.manipulate_lines(window, cx, |lines| {
 9868            let mut seen = HashSet::default();
 9869            lines.retain(|line| seen.insert(*line));
 9870        })
 9871    }
 9872
 9873    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9874        let Some(project) = self.project.clone() else {
 9875            return;
 9876        };
 9877        self.reload(project, window, cx)
 9878            .detach_and_notify_err(window, cx);
 9879    }
 9880
 9881    pub fn restore_file(
 9882        &mut self,
 9883        _: &::git::RestoreFile,
 9884        window: &mut Window,
 9885        cx: &mut Context<Self>,
 9886    ) {
 9887        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9888        let mut buffer_ids = HashSet::default();
 9889        let snapshot = self.buffer().read(cx).snapshot(cx);
 9890        for selection in self.selections.all::<usize>(cx) {
 9891            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9892        }
 9893
 9894        let buffer = self.buffer().read(cx);
 9895        let ranges = buffer_ids
 9896            .into_iter()
 9897            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9898            .collect::<Vec<_>>();
 9899
 9900        self.restore_hunks_in_ranges(ranges, window, cx);
 9901    }
 9902
 9903    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9904        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9905        let selections = self
 9906            .selections
 9907            .all(cx)
 9908            .into_iter()
 9909            .map(|s| s.range())
 9910            .collect();
 9911        self.restore_hunks_in_ranges(selections, window, cx);
 9912    }
 9913
 9914    pub fn restore_hunks_in_ranges(
 9915        &mut self,
 9916        ranges: Vec<Range<Point>>,
 9917        window: &mut Window,
 9918        cx: &mut Context<Editor>,
 9919    ) {
 9920        let mut revert_changes = HashMap::default();
 9921        let chunk_by = self
 9922            .snapshot(window, cx)
 9923            .hunks_for_ranges(ranges)
 9924            .into_iter()
 9925            .chunk_by(|hunk| hunk.buffer_id);
 9926        for (buffer_id, hunks) in &chunk_by {
 9927            let hunks = hunks.collect::<Vec<_>>();
 9928            for hunk in &hunks {
 9929                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9930            }
 9931            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9932        }
 9933        drop(chunk_by);
 9934        if !revert_changes.is_empty() {
 9935            self.transact(window, cx, |editor, window, cx| {
 9936                editor.restore(revert_changes, window, cx);
 9937            });
 9938        }
 9939    }
 9940
 9941    pub fn open_active_item_in_terminal(
 9942        &mut self,
 9943        _: &OpenInTerminal,
 9944        window: &mut Window,
 9945        cx: &mut Context<Self>,
 9946    ) {
 9947        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9948            let project_path = buffer.read(cx).project_path(cx)?;
 9949            let project = self.project.as_ref()?.read(cx);
 9950            let entry = project.entry_for_path(&project_path, cx)?;
 9951            let parent = match &entry.canonical_path {
 9952                Some(canonical_path) => canonical_path.to_path_buf(),
 9953                None => project.absolute_path(&project_path, cx)?,
 9954            }
 9955            .parent()?
 9956            .to_path_buf();
 9957            Some(parent)
 9958        }) {
 9959            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9960        }
 9961    }
 9962
 9963    fn set_breakpoint_context_menu(
 9964        &mut self,
 9965        display_row: DisplayRow,
 9966        position: Option<Anchor>,
 9967        clicked_point: gpui::Point<Pixels>,
 9968        window: &mut Window,
 9969        cx: &mut Context<Self>,
 9970    ) {
 9971        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9972            return;
 9973        }
 9974        let source = self
 9975            .buffer
 9976            .read(cx)
 9977            .snapshot(cx)
 9978            .anchor_before(Point::new(display_row.0, 0u32));
 9979
 9980        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9981
 9982        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9983            self,
 9984            source,
 9985            clicked_point,
 9986            context_menu,
 9987            window,
 9988            cx,
 9989        );
 9990    }
 9991
 9992    fn add_edit_breakpoint_block(
 9993        &mut self,
 9994        anchor: Anchor,
 9995        breakpoint: &Breakpoint,
 9996        edit_action: BreakpointPromptEditAction,
 9997        window: &mut Window,
 9998        cx: &mut Context<Self>,
 9999    ) {
10000        let weak_editor = cx.weak_entity();
10001        let bp_prompt = cx.new(|cx| {
10002            BreakpointPromptEditor::new(
10003                weak_editor,
10004                anchor,
10005                breakpoint.clone(),
10006                edit_action,
10007                window,
10008                cx,
10009            )
10010        });
10011
10012        let height = bp_prompt.update(cx, |this, cx| {
10013            this.prompt
10014                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10015        });
10016        let cloned_prompt = bp_prompt.clone();
10017        let blocks = vec![BlockProperties {
10018            style: BlockStyle::Sticky,
10019            placement: BlockPlacement::Above(anchor),
10020            height: Some(height),
10021            render: Arc::new(move |cx| {
10022                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10023                cloned_prompt.clone().into_any_element()
10024            }),
10025            priority: 0,
10026            render_in_minimap: true,
10027        }];
10028
10029        let focus_handle = bp_prompt.focus_handle(cx);
10030        window.focus(&focus_handle);
10031
10032        let block_ids = self.insert_blocks(blocks, None, cx);
10033        bp_prompt.update(cx, |prompt, _| {
10034            prompt.add_block_ids(block_ids);
10035        });
10036    }
10037
10038    pub(crate) fn breakpoint_at_row(
10039        &self,
10040        row: u32,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) -> Option<(Anchor, Breakpoint)> {
10044        let snapshot = self.snapshot(window, cx);
10045        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10046
10047        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10048    }
10049
10050    pub(crate) fn breakpoint_at_anchor(
10051        &self,
10052        breakpoint_position: Anchor,
10053        snapshot: &EditorSnapshot,
10054        cx: &mut Context<Self>,
10055    ) -> Option<(Anchor, Breakpoint)> {
10056        let project = self.project.clone()?;
10057
10058        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10059            snapshot
10060                .buffer_snapshot
10061                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10062        })?;
10063
10064        let enclosing_excerpt = breakpoint_position.excerpt_id;
10065        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10066        let buffer_snapshot = buffer.read(cx).snapshot();
10067
10068        let row = buffer_snapshot
10069            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10070            .row;
10071
10072        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10073        let anchor_end = snapshot
10074            .buffer_snapshot
10075            .anchor_after(Point::new(row, line_len));
10076
10077        let bp = self
10078            .breakpoint_store
10079            .as_ref()?
10080            .read_with(cx, |breakpoint_store, cx| {
10081                breakpoint_store
10082                    .breakpoints(
10083                        &buffer,
10084                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10085                        &buffer_snapshot,
10086                        cx,
10087                    )
10088                    .next()
10089                    .and_then(|(bp, _)| {
10090                        let breakpoint_row = buffer_snapshot
10091                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10092                            .row;
10093
10094                        if breakpoint_row == row {
10095                            snapshot
10096                                .buffer_snapshot
10097                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10098                                .map(|position| (position, bp.bp.clone()))
10099                        } else {
10100                            None
10101                        }
10102                    })
10103            });
10104        bp
10105    }
10106
10107    pub fn edit_log_breakpoint(
10108        &mut self,
10109        _: &EditLogBreakpoint,
10110        window: &mut Window,
10111        cx: &mut Context<Self>,
10112    ) {
10113        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10114            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10115                message: None,
10116                state: BreakpointState::Enabled,
10117                condition: None,
10118                hit_condition: None,
10119            });
10120
10121            self.add_edit_breakpoint_block(
10122                anchor,
10123                &breakpoint,
10124                BreakpointPromptEditAction::Log,
10125                window,
10126                cx,
10127            );
10128        }
10129    }
10130
10131    fn breakpoints_at_cursors(
10132        &self,
10133        window: &mut Window,
10134        cx: &mut Context<Self>,
10135    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10136        let snapshot = self.snapshot(window, cx);
10137        let cursors = self
10138            .selections
10139            .disjoint_anchors()
10140            .into_iter()
10141            .map(|selection| {
10142                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10143
10144                let breakpoint_position = self
10145                    .breakpoint_at_row(cursor_position.row, window, cx)
10146                    .map(|bp| bp.0)
10147                    .unwrap_or_else(|| {
10148                        snapshot
10149                            .display_snapshot
10150                            .buffer_snapshot
10151                            .anchor_after(Point::new(cursor_position.row, 0))
10152                    });
10153
10154                let breakpoint = self
10155                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10156                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10157
10158                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10159            })
10160            // 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.
10161            .collect::<HashMap<Anchor, _>>();
10162
10163        cursors.into_iter().collect()
10164    }
10165
10166    pub fn enable_breakpoint(
10167        &mut self,
10168        _: &crate::actions::EnableBreakpoint,
10169        window: &mut Window,
10170        cx: &mut Context<Self>,
10171    ) {
10172        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10173            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10174                continue;
10175            };
10176            self.edit_breakpoint_at_anchor(
10177                anchor,
10178                breakpoint,
10179                BreakpointEditAction::InvertState,
10180                cx,
10181            );
10182        }
10183    }
10184
10185    pub fn disable_breakpoint(
10186        &mut self,
10187        _: &crate::actions::DisableBreakpoint,
10188        window: &mut Window,
10189        cx: &mut Context<Self>,
10190    ) {
10191        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10192            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10193                continue;
10194            };
10195            self.edit_breakpoint_at_anchor(
10196                anchor,
10197                breakpoint,
10198                BreakpointEditAction::InvertState,
10199                cx,
10200            );
10201        }
10202    }
10203
10204    pub fn toggle_breakpoint(
10205        &mut self,
10206        _: &crate::actions::ToggleBreakpoint,
10207        window: &mut Window,
10208        cx: &mut Context<Self>,
10209    ) {
10210        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10211            if let Some(breakpoint) = breakpoint {
10212                self.edit_breakpoint_at_anchor(
10213                    anchor,
10214                    breakpoint,
10215                    BreakpointEditAction::Toggle,
10216                    cx,
10217                );
10218            } else {
10219                self.edit_breakpoint_at_anchor(
10220                    anchor,
10221                    Breakpoint::new_standard(),
10222                    BreakpointEditAction::Toggle,
10223                    cx,
10224                );
10225            }
10226        }
10227    }
10228
10229    pub fn edit_breakpoint_at_anchor(
10230        &mut self,
10231        breakpoint_position: Anchor,
10232        breakpoint: Breakpoint,
10233        edit_action: BreakpointEditAction,
10234        cx: &mut Context<Self>,
10235    ) {
10236        let Some(breakpoint_store) = &self.breakpoint_store else {
10237            return;
10238        };
10239
10240        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10241            if breakpoint_position == Anchor::min() {
10242                self.buffer()
10243                    .read(cx)
10244                    .excerpt_buffer_ids()
10245                    .into_iter()
10246                    .next()
10247            } else {
10248                None
10249            }
10250        }) else {
10251            return;
10252        };
10253
10254        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10255            return;
10256        };
10257
10258        breakpoint_store.update(cx, |breakpoint_store, cx| {
10259            breakpoint_store.toggle_breakpoint(
10260                buffer,
10261                BreakpointWithPosition {
10262                    position: breakpoint_position.text_anchor,
10263                    bp: breakpoint,
10264                },
10265                edit_action,
10266                cx,
10267            );
10268        });
10269
10270        cx.notify();
10271    }
10272
10273    #[cfg(any(test, feature = "test-support"))]
10274    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10275        self.breakpoint_store.clone()
10276    }
10277
10278    pub fn prepare_restore_change(
10279        &self,
10280        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10281        hunk: &MultiBufferDiffHunk,
10282        cx: &mut App,
10283    ) -> Option<()> {
10284        if hunk.is_created_file() {
10285            return None;
10286        }
10287        let buffer = self.buffer.read(cx);
10288        let diff = buffer.diff_for(hunk.buffer_id)?;
10289        let buffer = buffer.buffer(hunk.buffer_id)?;
10290        let buffer = buffer.read(cx);
10291        let original_text = diff
10292            .read(cx)
10293            .base_text()
10294            .as_rope()
10295            .slice(hunk.diff_base_byte_range.clone());
10296        let buffer_snapshot = buffer.snapshot();
10297        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10298        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10299            probe
10300                .0
10301                .start
10302                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10303                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10304        }) {
10305            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10306            Some(())
10307        } else {
10308            None
10309        }
10310    }
10311
10312    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10313        self.manipulate_lines(window, cx, |lines| lines.reverse())
10314    }
10315
10316    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10317        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10318    }
10319
10320    fn manipulate_lines<Fn>(
10321        &mut self,
10322        window: &mut Window,
10323        cx: &mut Context<Self>,
10324        mut callback: Fn,
10325    ) where
10326        Fn: FnMut(&mut Vec<&str>),
10327    {
10328        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10329
10330        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10331        let buffer = self.buffer.read(cx).snapshot(cx);
10332
10333        let mut edits = Vec::new();
10334
10335        let selections = self.selections.all::<Point>(cx);
10336        let mut selections = selections.iter().peekable();
10337        let mut contiguous_row_selections = Vec::new();
10338        let mut new_selections = Vec::new();
10339        let mut added_lines = 0;
10340        let mut removed_lines = 0;
10341
10342        while let Some(selection) = selections.next() {
10343            let (start_row, end_row) = consume_contiguous_rows(
10344                &mut contiguous_row_selections,
10345                selection,
10346                &display_map,
10347                &mut selections,
10348            );
10349
10350            let start_point = Point::new(start_row.0, 0);
10351            let end_point = Point::new(
10352                end_row.previous_row().0,
10353                buffer.line_len(end_row.previous_row()),
10354            );
10355            let text = buffer
10356                .text_for_range(start_point..end_point)
10357                .collect::<String>();
10358
10359            let mut lines = text.split('\n').collect_vec();
10360
10361            let lines_before = lines.len();
10362            callback(&mut lines);
10363            let lines_after = lines.len();
10364
10365            edits.push((start_point..end_point, lines.join("\n")));
10366
10367            // Selections must change based on added and removed line count
10368            let start_row =
10369                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10370            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10371            new_selections.push(Selection {
10372                id: selection.id,
10373                start: start_row,
10374                end: end_row,
10375                goal: SelectionGoal::None,
10376                reversed: selection.reversed,
10377            });
10378
10379            if lines_after > lines_before {
10380                added_lines += lines_after - lines_before;
10381            } else if lines_before > lines_after {
10382                removed_lines += lines_before - lines_after;
10383            }
10384        }
10385
10386        self.transact(window, cx, |this, window, cx| {
10387            let buffer = this.buffer.update(cx, |buffer, cx| {
10388                buffer.edit(edits, None, cx);
10389                buffer.snapshot(cx)
10390            });
10391
10392            // Recalculate offsets on newly edited buffer
10393            let new_selections = new_selections
10394                .iter()
10395                .map(|s| {
10396                    let start_point = Point::new(s.start.0, 0);
10397                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10398                    Selection {
10399                        id: s.id,
10400                        start: buffer.point_to_offset(start_point),
10401                        end: buffer.point_to_offset(end_point),
10402                        goal: s.goal,
10403                        reversed: s.reversed,
10404                    }
10405                })
10406                .collect();
10407
10408            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10409                s.select(new_selections);
10410            });
10411
10412            this.request_autoscroll(Autoscroll::fit(), cx);
10413        });
10414    }
10415
10416    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10417        self.manipulate_text(window, cx, |text| {
10418            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10419            if has_upper_case_characters {
10420                text.to_lowercase()
10421            } else {
10422                text.to_uppercase()
10423            }
10424        })
10425    }
10426
10427    pub fn convert_to_upper_case(
10428        &mut self,
10429        _: &ConvertToUpperCase,
10430        window: &mut Window,
10431        cx: &mut Context<Self>,
10432    ) {
10433        self.manipulate_text(window, cx, |text| text.to_uppercase())
10434    }
10435
10436    pub fn convert_to_lower_case(
10437        &mut self,
10438        _: &ConvertToLowerCase,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) {
10442        self.manipulate_text(window, cx, |text| text.to_lowercase())
10443    }
10444
10445    pub fn convert_to_title_case(
10446        &mut self,
10447        _: &ConvertToTitleCase,
10448        window: &mut Window,
10449        cx: &mut Context<Self>,
10450    ) {
10451        self.manipulate_text(window, cx, |text| {
10452            text.split('\n')
10453                .map(|line| line.to_case(Case::Title))
10454                .join("\n")
10455        })
10456    }
10457
10458    pub fn convert_to_snake_case(
10459        &mut self,
10460        _: &ConvertToSnakeCase,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10465    }
10466
10467    pub fn convert_to_kebab_case(
10468        &mut self,
10469        _: &ConvertToKebabCase,
10470        window: &mut Window,
10471        cx: &mut Context<Self>,
10472    ) {
10473        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10474    }
10475
10476    pub fn convert_to_upper_camel_case(
10477        &mut self,
10478        _: &ConvertToUpperCamelCase,
10479        window: &mut Window,
10480        cx: &mut Context<Self>,
10481    ) {
10482        self.manipulate_text(window, cx, |text| {
10483            text.split('\n')
10484                .map(|line| line.to_case(Case::UpperCamel))
10485                .join("\n")
10486        })
10487    }
10488
10489    pub fn convert_to_lower_camel_case(
10490        &mut self,
10491        _: &ConvertToLowerCamelCase,
10492        window: &mut Window,
10493        cx: &mut Context<Self>,
10494    ) {
10495        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10496    }
10497
10498    pub fn convert_to_opposite_case(
10499        &mut self,
10500        _: &ConvertToOppositeCase,
10501        window: &mut Window,
10502        cx: &mut Context<Self>,
10503    ) {
10504        self.manipulate_text(window, cx, |text| {
10505            text.chars()
10506                .fold(String::with_capacity(text.len()), |mut t, c| {
10507                    if c.is_uppercase() {
10508                        t.extend(c.to_lowercase());
10509                    } else {
10510                        t.extend(c.to_uppercase());
10511                    }
10512                    t
10513                })
10514        })
10515    }
10516
10517    pub fn convert_to_rot13(
10518        &mut self,
10519        _: &ConvertToRot13,
10520        window: &mut Window,
10521        cx: &mut Context<Self>,
10522    ) {
10523        self.manipulate_text(window, cx, |text| {
10524            text.chars()
10525                .map(|c| match c {
10526                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10527                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10528                    _ => c,
10529                })
10530                .collect()
10531        })
10532    }
10533
10534    pub fn convert_to_rot47(
10535        &mut self,
10536        _: &ConvertToRot47,
10537        window: &mut Window,
10538        cx: &mut Context<Self>,
10539    ) {
10540        self.manipulate_text(window, cx, |text| {
10541            text.chars()
10542                .map(|c| {
10543                    let code_point = c as u32;
10544                    if code_point >= 33 && code_point <= 126 {
10545                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10546                    }
10547                    c
10548                })
10549                .collect()
10550        })
10551    }
10552
10553    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10554    where
10555        Fn: FnMut(&str) -> String,
10556    {
10557        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10558        let buffer = self.buffer.read(cx).snapshot(cx);
10559
10560        let mut new_selections = Vec::new();
10561        let mut edits = Vec::new();
10562        let mut selection_adjustment = 0i32;
10563
10564        for selection in self.selections.all::<usize>(cx) {
10565            let selection_is_empty = selection.is_empty();
10566
10567            let (start, end) = if selection_is_empty {
10568                let word_range = movement::surrounding_word(
10569                    &display_map,
10570                    selection.start.to_display_point(&display_map),
10571                );
10572                let start = word_range.start.to_offset(&display_map, Bias::Left);
10573                let end = word_range.end.to_offset(&display_map, Bias::Left);
10574                (start, end)
10575            } else {
10576                (selection.start, selection.end)
10577            };
10578
10579            let text = buffer.text_for_range(start..end).collect::<String>();
10580            let old_length = text.len() as i32;
10581            let text = callback(&text);
10582
10583            new_selections.push(Selection {
10584                start: (start as i32 - selection_adjustment) as usize,
10585                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10586                goal: SelectionGoal::None,
10587                ..selection
10588            });
10589
10590            selection_adjustment += old_length - text.len() as i32;
10591
10592            edits.push((start..end, text));
10593        }
10594
10595        self.transact(window, cx, |this, window, cx| {
10596            this.buffer.update(cx, |buffer, cx| {
10597                buffer.edit(edits, None, cx);
10598            });
10599
10600            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10601                s.select(new_selections);
10602            });
10603
10604            this.request_autoscroll(Autoscroll::fit(), cx);
10605        });
10606    }
10607
10608    pub fn move_selection_on_drop(
10609        &mut self,
10610        selection: &Selection<Anchor>,
10611        target: DisplayPoint,
10612        is_cut: bool,
10613        window: &mut Window,
10614        cx: &mut Context<Self>,
10615    ) {
10616        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10617        let buffer = &display_map.buffer_snapshot;
10618        let mut edits = Vec::new();
10619        let insert_point = display_map
10620            .clip_point(target, Bias::Left)
10621            .to_point(&display_map);
10622        let text = buffer
10623            .text_for_range(selection.start..selection.end)
10624            .collect::<String>();
10625        if is_cut {
10626            edits.push(((selection.start..selection.end), String::new()));
10627        }
10628        let insert_anchor = buffer.anchor_before(insert_point);
10629        edits.push(((insert_anchor..insert_anchor), text));
10630        let last_edit_start = insert_anchor.bias_left(buffer);
10631        let last_edit_end = insert_anchor.bias_right(buffer);
10632        self.transact(window, cx, |this, window, cx| {
10633            this.buffer.update(cx, |buffer, cx| {
10634                buffer.edit(edits, None, cx);
10635            });
10636            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10637                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10638            });
10639        });
10640    }
10641
10642    pub fn clear_selection_drag_state(&mut self) {
10643        self.selection_drag_state = SelectionDragState::None;
10644    }
10645
10646    pub fn duplicate(
10647        &mut self,
10648        upwards: bool,
10649        whole_lines: bool,
10650        window: &mut Window,
10651        cx: &mut Context<Self>,
10652    ) {
10653        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10654
10655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10656        let buffer = &display_map.buffer_snapshot;
10657        let selections = self.selections.all::<Point>(cx);
10658
10659        let mut edits = Vec::new();
10660        let mut selections_iter = selections.iter().peekable();
10661        while let Some(selection) = selections_iter.next() {
10662            let mut rows = selection.spanned_rows(false, &display_map);
10663            // duplicate line-wise
10664            if whole_lines || selection.start == selection.end {
10665                // Avoid duplicating the same lines twice.
10666                while let Some(next_selection) = selections_iter.peek() {
10667                    let next_rows = next_selection.spanned_rows(false, &display_map);
10668                    if next_rows.start < rows.end {
10669                        rows.end = next_rows.end;
10670                        selections_iter.next().unwrap();
10671                    } else {
10672                        break;
10673                    }
10674                }
10675
10676                // Copy the text from the selected row region and splice it either at the start
10677                // or end of the region.
10678                let start = Point::new(rows.start.0, 0);
10679                let end = Point::new(
10680                    rows.end.previous_row().0,
10681                    buffer.line_len(rows.end.previous_row()),
10682                );
10683                let text = buffer
10684                    .text_for_range(start..end)
10685                    .chain(Some("\n"))
10686                    .collect::<String>();
10687                let insert_location = if upwards {
10688                    Point::new(rows.end.0, 0)
10689                } else {
10690                    start
10691                };
10692                edits.push((insert_location..insert_location, text));
10693            } else {
10694                // duplicate character-wise
10695                let start = selection.start;
10696                let end = selection.end;
10697                let text = buffer.text_for_range(start..end).collect::<String>();
10698                edits.push((selection.end..selection.end, text));
10699            }
10700        }
10701
10702        self.transact(window, cx, |this, _, cx| {
10703            this.buffer.update(cx, |buffer, cx| {
10704                buffer.edit(edits, None, cx);
10705            });
10706
10707            this.request_autoscroll(Autoscroll::fit(), cx);
10708        });
10709    }
10710
10711    pub fn duplicate_line_up(
10712        &mut self,
10713        _: &DuplicateLineUp,
10714        window: &mut Window,
10715        cx: &mut Context<Self>,
10716    ) {
10717        self.duplicate(true, true, window, cx);
10718    }
10719
10720    pub fn duplicate_line_down(
10721        &mut self,
10722        _: &DuplicateLineDown,
10723        window: &mut Window,
10724        cx: &mut Context<Self>,
10725    ) {
10726        self.duplicate(false, true, window, cx);
10727    }
10728
10729    pub fn duplicate_selection(
10730        &mut self,
10731        _: &DuplicateSelection,
10732        window: &mut Window,
10733        cx: &mut Context<Self>,
10734    ) {
10735        self.duplicate(false, false, window, cx);
10736    }
10737
10738    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10739        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10740
10741        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10742        let buffer = self.buffer.read(cx).snapshot(cx);
10743
10744        let mut edits = Vec::new();
10745        let mut unfold_ranges = Vec::new();
10746        let mut refold_creases = Vec::new();
10747
10748        let selections = self.selections.all::<Point>(cx);
10749        let mut selections = selections.iter().peekable();
10750        let mut contiguous_row_selections = Vec::new();
10751        let mut new_selections = Vec::new();
10752
10753        while let Some(selection) = selections.next() {
10754            // Find all the selections that span a contiguous row range
10755            let (start_row, end_row) = consume_contiguous_rows(
10756                &mut contiguous_row_selections,
10757                selection,
10758                &display_map,
10759                &mut selections,
10760            );
10761
10762            // Move the text spanned by the row range to be before the line preceding the row range
10763            if start_row.0 > 0 {
10764                let range_to_move = Point::new(
10765                    start_row.previous_row().0,
10766                    buffer.line_len(start_row.previous_row()),
10767                )
10768                    ..Point::new(
10769                        end_row.previous_row().0,
10770                        buffer.line_len(end_row.previous_row()),
10771                    );
10772                let insertion_point = display_map
10773                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10774                    .0;
10775
10776                // Don't move lines across excerpts
10777                if buffer
10778                    .excerpt_containing(insertion_point..range_to_move.end)
10779                    .is_some()
10780                {
10781                    let text = buffer
10782                        .text_for_range(range_to_move.clone())
10783                        .flat_map(|s| s.chars())
10784                        .skip(1)
10785                        .chain(['\n'])
10786                        .collect::<String>();
10787
10788                    edits.push((
10789                        buffer.anchor_after(range_to_move.start)
10790                            ..buffer.anchor_before(range_to_move.end),
10791                        String::new(),
10792                    ));
10793                    let insertion_anchor = buffer.anchor_after(insertion_point);
10794                    edits.push((insertion_anchor..insertion_anchor, text));
10795
10796                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10797
10798                    // Move selections up
10799                    new_selections.extend(contiguous_row_selections.drain(..).map(
10800                        |mut selection| {
10801                            selection.start.row -= row_delta;
10802                            selection.end.row -= row_delta;
10803                            selection
10804                        },
10805                    ));
10806
10807                    // Move folds up
10808                    unfold_ranges.push(range_to_move.clone());
10809                    for fold in display_map.folds_in_range(
10810                        buffer.anchor_before(range_to_move.start)
10811                            ..buffer.anchor_after(range_to_move.end),
10812                    ) {
10813                        let mut start = fold.range.start.to_point(&buffer);
10814                        let mut end = fold.range.end.to_point(&buffer);
10815                        start.row -= row_delta;
10816                        end.row -= row_delta;
10817                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10818                    }
10819                }
10820            }
10821
10822            // If we didn't move line(s), preserve the existing selections
10823            new_selections.append(&mut contiguous_row_selections);
10824        }
10825
10826        self.transact(window, cx, |this, window, cx| {
10827            this.unfold_ranges(&unfold_ranges, true, true, cx);
10828            this.buffer.update(cx, |buffer, cx| {
10829                for (range, text) in edits {
10830                    buffer.edit([(range, text)], None, cx);
10831                }
10832            });
10833            this.fold_creases(refold_creases, true, window, cx);
10834            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10835                s.select(new_selections);
10836            })
10837        });
10838    }
10839
10840    pub fn move_line_down(
10841        &mut self,
10842        _: &MoveLineDown,
10843        window: &mut Window,
10844        cx: &mut Context<Self>,
10845    ) {
10846        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10847
10848        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10849        let buffer = self.buffer.read(cx).snapshot(cx);
10850
10851        let mut edits = Vec::new();
10852        let mut unfold_ranges = Vec::new();
10853        let mut refold_creases = Vec::new();
10854
10855        let selections = self.selections.all::<Point>(cx);
10856        let mut selections = selections.iter().peekable();
10857        let mut contiguous_row_selections = Vec::new();
10858        let mut new_selections = Vec::new();
10859
10860        while let Some(selection) = selections.next() {
10861            // Find all the selections that span a contiguous row range
10862            let (start_row, end_row) = consume_contiguous_rows(
10863                &mut contiguous_row_selections,
10864                selection,
10865                &display_map,
10866                &mut selections,
10867            );
10868
10869            // Move the text spanned by the row range to be after the last line of the row range
10870            if end_row.0 <= buffer.max_point().row {
10871                let range_to_move =
10872                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10873                let insertion_point = display_map
10874                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10875                    .0;
10876
10877                // Don't move lines across excerpt boundaries
10878                if buffer
10879                    .excerpt_containing(range_to_move.start..insertion_point)
10880                    .is_some()
10881                {
10882                    let mut text = String::from("\n");
10883                    text.extend(buffer.text_for_range(range_to_move.clone()));
10884                    text.pop(); // Drop trailing newline
10885                    edits.push((
10886                        buffer.anchor_after(range_to_move.start)
10887                            ..buffer.anchor_before(range_to_move.end),
10888                        String::new(),
10889                    ));
10890                    let insertion_anchor = buffer.anchor_after(insertion_point);
10891                    edits.push((insertion_anchor..insertion_anchor, text));
10892
10893                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10894
10895                    // Move selections down
10896                    new_selections.extend(contiguous_row_selections.drain(..).map(
10897                        |mut selection| {
10898                            selection.start.row += row_delta;
10899                            selection.end.row += row_delta;
10900                            selection
10901                        },
10902                    ));
10903
10904                    // Move folds down
10905                    unfold_ranges.push(range_to_move.clone());
10906                    for fold in display_map.folds_in_range(
10907                        buffer.anchor_before(range_to_move.start)
10908                            ..buffer.anchor_after(range_to_move.end),
10909                    ) {
10910                        let mut start = fold.range.start.to_point(&buffer);
10911                        let mut end = fold.range.end.to_point(&buffer);
10912                        start.row += row_delta;
10913                        end.row += row_delta;
10914                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10915                    }
10916                }
10917            }
10918
10919            // If we didn't move line(s), preserve the existing selections
10920            new_selections.append(&mut contiguous_row_selections);
10921        }
10922
10923        self.transact(window, cx, |this, window, cx| {
10924            this.unfold_ranges(&unfold_ranges, true, true, cx);
10925            this.buffer.update(cx, |buffer, cx| {
10926                for (range, text) in edits {
10927                    buffer.edit([(range, text)], None, cx);
10928                }
10929            });
10930            this.fold_creases(refold_creases, true, window, cx);
10931            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10932                s.select(new_selections)
10933            });
10934        });
10935    }
10936
10937    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10938        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10939        let text_layout_details = &self.text_layout_details(window);
10940        self.transact(window, cx, |this, window, cx| {
10941            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10942                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10943                s.move_with(|display_map, selection| {
10944                    if !selection.is_empty() {
10945                        return;
10946                    }
10947
10948                    let mut head = selection.head();
10949                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10950                    if head.column() == display_map.line_len(head.row()) {
10951                        transpose_offset = display_map
10952                            .buffer_snapshot
10953                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10954                    }
10955
10956                    if transpose_offset == 0 {
10957                        return;
10958                    }
10959
10960                    *head.column_mut() += 1;
10961                    head = display_map.clip_point(head, Bias::Right);
10962                    let goal = SelectionGoal::HorizontalPosition(
10963                        display_map
10964                            .x_for_display_point(head, text_layout_details)
10965                            .into(),
10966                    );
10967                    selection.collapse_to(head, goal);
10968
10969                    let transpose_start = display_map
10970                        .buffer_snapshot
10971                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10972                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10973                        let transpose_end = display_map
10974                            .buffer_snapshot
10975                            .clip_offset(transpose_offset + 1, Bias::Right);
10976                        if let Some(ch) =
10977                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10978                        {
10979                            edits.push((transpose_start..transpose_offset, String::new()));
10980                            edits.push((transpose_end..transpose_end, ch.to_string()));
10981                        }
10982                    }
10983                });
10984                edits
10985            });
10986            this.buffer
10987                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10988            let selections = this.selections.all::<usize>(cx);
10989            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10990                s.select(selections);
10991            });
10992        });
10993    }
10994
10995    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10996        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10997        self.rewrap_impl(RewrapOptions::default(), cx)
10998    }
10999
11000    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11001        let buffer = self.buffer.read(cx).snapshot(cx);
11002        let selections = self.selections.all::<Point>(cx);
11003
11004        // Shrink and split selections to respect paragraph boundaries.
11005        let ranges = selections.into_iter().flat_map(|selection| {
11006            let language_settings = buffer.language_settings_at(selection.head(), cx);
11007            let language_scope = buffer.language_scope_at(selection.head());
11008
11009            let Some(start_row) = (selection.start.row..=selection.end.row)
11010                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11011            else {
11012                return vec![];
11013            };
11014            let Some(end_row) = (selection.start.row..=selection.end.row)
11015                .rev()
11016                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11017            else {
11018                return vec![];
11019            };
11020
11021            let mut row = start_row;
11022            let mut ranges = Vec::new();
11023            while let Some(blank_row) =
11024                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11025            {
11026                let next_paragraph_start = (blank_row + 1..=end_row)
11027                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11028                    .unwrap();
11029                ranges.push((
11030                    language_settings.clone(),
11031                    language_scope.clone(),
11032                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11033                ));
11034                row = next_paragraph_start;
11035            }
11036            ranges.push((
11037                language_settings.clone(),
11038                language_scope.clone(),
11039                Point::new(row, 0)..Point::new(end_row, 0),
11040            ));
11041
11042            ranges
11043        });
11044
11045        let mut edits = Vec::new();
11046        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11047
11048        for (language_settings, language_scope, range) in ranges {
11049            let mut start_row = range.start.row;
11050            let mut end_row = range.end.row;
11051
11052            // Skip selections that overlap with a range that has already been rewrapped.
11053            let selection_range = start_row..end_row;
11054            if rewrapped_row_ranges
11055                .iter()
11056                .any(|range| range.overlaps(&selection_range))
11057            {
11058                continue;
11059            }
11060
11061            let tab_size = language_settings.tab_size;
11062
11063            // Since not all lines in the selection may be at the same indent
11064            // level, choose the indent size that is the most common between all
11065            // of the lines.
11066            //
11067            // If there is a tie, we use the deepest indent.
11068            let (indent_size, indent_end) = {
11069                let mut indent_size_occurrences = HashMap::default();
11070                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11071
11072                for row in start_row..=end_row {
11073                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11074                    rows_by_indent_size.entry(indent).or_default().push(row);
11075                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11076                }
11077
11078                let indent_size = indent_size_occurrences
11079                    .into_iter()
11080                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11081                    .map(|(indent, _)| indent)
11082                    .unwrap_or_default();
11083                let row = rows_by_indent_size[&indent_size][0];
11084                let indent_end = Point::new(row, indent_size.len);
11085
11086                (indent_size, indent_end)
11087            };
11088
11089            let mut line_prefix = indent_size.chars().collect::<String>();
11090
11091            let mut inside_comment = false;
11092            if let Some(comment_prefix) = language_scope.and_then(|language| {
11093                language
11094                    .line_comment_prefixes()
11095                    .iter()
11096                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11097                    .cloned()
11098            }) {
11099                line_prefix.push_str(&comment_prefix);
11100                inside_comment = true;
11101            }
11102
11103            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11104                RewrapBehavior::InComments => inside_comment,
11105                RewrapBehavior::InSelections => !range.is_empty(),
11106                RewrapBehavior::Anywhere => true,
11107            };
11108
11109            let should_rewrap = options.override_language_settings
11110                || allow_rewrap_based_on_language
11111                || self.hard_wrap.is_some();
11112            if !should_rewrap {
11113                continue;
11114            }
11115
11116            if range.is_empty() {
11117                'expand_upwards: while start_row > 0 {
11118                    let prev_row = start_row - 1;
11119                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11120                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11121                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11122                    {
11123                        start_row = prev_row;
11124                    } else {
11125                        break 'expand_upwards;
11126                    }
11127                }
11128
11129                'expand_downwards: while end_row < buffer.max_point().row {
11130                    let next_row = end_row + 1;
11131                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11132                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11133                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11134                    {
11135                        end_row = next_row;
11136                    } else {
11137                        break 'expand_downwards;
11138                    }
11139                }
11140            }
11141
11142            let start = Point::new(start_row, 0);
11143            let start_offset = start.to_offset(&buffer);
11144            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11145            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11146            let Some(lines_without_prefixes) = selection_text
11147                .lines()
11148                .map(|line| {
11149                    line.strip_prefix(&line_prefix)
11150                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11151                        .with_context(|| {
11152                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11153                        })
11154                })
11155                .collect::<Result<Vec<_>, _>>()
11156                .log_err()
11157            else {
11158                continue;
11159            };
11160
11161            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11162                buffer
11163                    .language_settings_at(Point::new(start_row, 0), cx)
11164                    .preferred_line_length as usize
11165            });
11166            let wrapped_text = wrap_with_prefix(
11167                line_prefix,
11168                lines_without_prefixes.join("\n"),
11169                wrap_column,
11170                tab_size,
11171                options.preserve_existing_whitespace,
11172            );
11173
11174            // TODO: should always use char-based diff while still supporting cursor behavior that
11175            // matches vim.
11176            let mut diff_options = DiffOptions::default();
11177            if options.override_language_settings {
11178                diff_options.max_word_diff_len = 0;
11179                diff_options.max_word_diff_line_count = 0;
11180            } else {
11181                diff_options.max_word_diff_len = usize::MAX;
11182                diff_options.max_word_diff_line_count = usize::MAX;
11183            }
11184
11185            for (old_range, new_text) in
11186                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11187            {
11188                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11189                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11190                edits.push((edit_start..edit_end, new_text));
11191            }
11192
11193            rewrapped_row_ranges.push(start_row..=end_row);
11194        }
11195
11196        self.buffer
11197            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11198    }
11199
11200    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11201        let mut text = String::new();
11202        let buffer = self.buffer.read(cx).snapshot(cx);
11203        let mut selections = self.selections.all::<Point>(cx);
11204        let mut clipboard_selections = Vec::with_capacity(selections.len());
11205        {
11206            let max_point = buffer.max_point();
11207            let mut is_first = true;
11208            for selection in &mut selections {
11209                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11210                if is_entire_line {
11211                    selection.start = Point::new(selection.start.row, 0);
11212                    if !selection.is_empty() && selection.end.column == 0 {
11213                        selection.end = cmp::min(max_point, selection.end);
11214                    } else {
11215                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11216                    }
11217                    selection.goal = SelectionGoal::None;
11218                }
11219                if is_first {
11220                    is_first = false;
11221                } else {
11222                    text += "\n";
11223                }
11224                let mut len = 0;
11225                for chunk in buffer.text_for_range(selection.start..selection.end) {
11226                    text.push_str(chunk);
11227                    len += chunk.len();
11228                }
11229                clipboard_selections.push(ClipboardSelection {
11230                    len,
11231                    is_entire_line,
11232                    first_line_indent: buffer
11233                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11234                        .len,
11235                });
11236            }
11237        }
11238
11239        self.transact(window, cx, |this, window, cx| {
11240            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11241                s.select(selections);
11242            });
11243            this.insert("", window, cx);
11244        });
11245        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11246    }
11247
11248    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11249        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11250        let item = self.cut_common(window, cx);
11251        cx.write_to_clipboard(item);
11252    }
11253
11254    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11255        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11256        self.change_selections(None, window, cx, |s| {
11257            s.move_with(|snapshot, sel| {
11258                if sel.is_empty() {
11259                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11260                }
11261            });
11262        });
11263        let item = self.cut_common(window, cx);
11264        cx.set_global(KillRing(item))
11265    }
11266
11267    pub fn kill_ring_yank(
11268        &mut self,
11269        _: &KillRingYank,
11270        window: &mut Window,
11271        cx: &mut Context<Self>,
11272    ) {
11273        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11274        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11275            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11276                (kill_ring.text().to_string(), kill_ring.metadata_json())
11277            } else {
11278                return;
11279            }
11280        } else {
11281            return;
11282        };
11283        self.do_paste(&text, metadata, false, window, cx);
11284    }
11285
11286    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11287        self.do_copy(true, cx);
11288    }
11289
11290    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11291        self.do_copy(false, cx);
11292    }
11293
11294    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11295        let selections = self.selections.all::<Point>(cx);
11296        let buffer = self.buffer.read(cx).read(cx);
11297        let mut text = String::new();
11298
11299        let mut clipboard_selections = Vec::with_capacity(selections.len());
11300        {
11301            let max_point = buffer.max_point();
11302            let mut is_first = true;
11303            for selection in &selections {
11304                let mut start = selection.start;
11305                let mut end = selection.end;
11306                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11307                if is_entire_line {
11308                    start = Point::new(start.row, 0);
11309                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11310                }
11311
11312                let mut trimmed_selections = Vec::new();
11313                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11314                    let row = MultiBufferRow(start.row);
11315                    let first_indent = buffer.indent_size_for_line(row);
11316                    if first_indent.len == 0 || start.column > first_indent.len {
11317                        trimmed_selections.push(start..end);
11318                    } else {
11319                        trimmed_selections.push(
11320                            Point::new(row.0, first_indent.len)
11321                                ..Point::new(row.0, buffer.line_len(row)),
11322                        );
11323                        for row in start.row + 1..=end.row {
11324                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11325                            if row == end.row {
11326                                line_len = end.column;
11327                            }
11328                            if line_len == 0 {
11329                                trimmed_selections
11330                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11331                                continue;
11332                            }
11333                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11334                            if row_indent_size.len >= first_indent.len {
11335                                trimmed_selections.push(
11336                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11337                                );
11338                            } else {
11339                                trimmed_selections.clear();
11340                                trimmed_selections.push(start..end);
11341                                break;
11342                            }
11343                        }
11344                    }
11345                } else {
11346                    trimmed_selections.push(start..end);
11347                }
11348
11349                for trimmed_range in trimmed_selections {
11350                    if is_first {
11351                        is_first = false;
11352                    } else {
11353                        text += "\n";
11354                    }
11355                    let mut len = 0;
11356                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11357                        text.push_str(chunk);
11358                        len += chunk.len();
11359                    }
11360                    clipboard_selections.push(ClipboardSelection {
11361                        len,
11362                        is_entire_line,
11363                        first_line_indent: buffer
11364                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11365                            .len,
11366                    });
11367                }
11368            }
11369        }
11370
11371        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11372            text,
11373            clipboard_selections,
11374        ));
11375    }
11376
11377    pub fn do_paste(
11378        &mut self,
11379        text: &String,
11380        clipboard_selections: Option<Vec<ClipboardSelection>>,
11381        handle_entire_lines: bool,
11382        window: &mut Window,
11383        cx: &mut Context<Self>,
11384    ) {
11385        if self.read_only(cx) {
11386            return;
11387        }
11388
11389        let clipboard_text = Cow::Borrowed(text);
11390
11391        self.transact(window, cx, |this, window, cx| {
11392            if let Some(mut clipboard_selections) = clipboard_selections {
11393                let old_selections = this.selections.all::<usize>(cx);
11394                let all_selections_were_entire_line =
11395                    clipboard_selections.iter().all(|s| s.is_entire_line);
11396                let first_selection_indent_column =
11397                    clipboard_selections.first().map(|s| s.first_line_indent);
11398                if clipboard_selections.len() != old_selections.len() {
11399                    clipboard_selections.drain(..);
11400                }
11401                let cursor_offset = this.selections.last::<usize>(cx).head();
11402                let mut auto_indent_on_paste = true;
11403
11404                this.buffer.update(cx, |buffer, cx| {
11405                    let snapshot = buffer.read(cx);
11406                    auto_indent_on_paste = snapshot
11407                        .language_settings_at(cursor_offset, cx)
11408                        .auto_indent_on_paste;
11409
11410                    let mut start_offset = 0;
11411                    let mut edits = Vec::new();
11412                    let mut original_indent_columns = Vec::new();
11413                    for (ix, selection) in old_selections.iter().enumerate() {
11414                        let to_insert;
11415                        let entire_line;
11416                        let original_indent_column;
11417                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11418                            let end_offset = start_offset + clipboard_selection.len;
11419                            to_insert = &clipboard_text[start_offset..end_offset];
11420                            entire_line = clipboard_selection.is_entire_line;
11421                            start_offset = end_offset + 1;
11422                            original_indent_column = Some(clipboard_selection.first_line_indent);
11423                        } else {
11424                            to_insert = clipboard_text.as_str();
11425                            entire_line = all_selections_were_entire_line;
11426                            original_indent_column = first_selection_indent_column
11427                        }
11428
11429                        // If the corresponding selection was empty when this slice of the
11430                        // clipboard text was written, then the entire line containing the
11431                        // selection was copied. If this selection is also currently empty,
11432                        // then paste the line before the current line of the buffer.
11433                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11434                            let column = selection.start.to_point(&snapshot).column as usize;
11435                            let line_start = selection.start - column;
11436                            line_start..line_start
11437                        } else {
11438                            selection.range()
11439                        };
11440
11441                        edits.push((range, to_insert));
11442                        original_indent_columns.push(original_indent_column);
11443                    }
11444                    drop(snapshot);
11445
11446                    buffer.edit(
11447                        edits,
11448                        if auto_indent_on_paste {
11449                            Some(AutoindentMode::Block {
11450                                original_indent_columns,
11451                            })
11452                        } else {
11453                            None
11454                        },
11455                        cx,
11456                    );
11457                });
11458
11459                let selections = this.selections.all::<usize>(cx);
11460                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11461                    s.select(selections)
11462                });
11463            } else {
11464                this.insert(&clipboard_text, window, cx);
11465            }
11466        });
11467    }
11468
11469    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11470        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11471        if let Some(item) = cx.read_from_clipboard() {
11472            let entries = item.entries();
11473
11474            match entries.first() {
11475                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11476                // of all the pasted entries.
11477                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11478                    .do_paste(
11479                        clipboard_string.text(),
11480                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11481                        true,
11482                        window,
11483                        cx,
11484                    ),
11485                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11486            }
11487        }
11488    }
11489
11490    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11491        if self.read_only(cx) {
11492            return;
11493        }
11494
11495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11496
11497        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11498            if let Some((selections, _)) =
11499                self.selection_history.transaction(transaction_id).cloned()
11500            {
11501                self.change_selections(None, window, cx, |s| {
11502                    s.select_anchors(selections.to_vec());
11503                });
11504            } else {
11505                log::error!(
11506                    "No entry in selection_history found for undo. \
11507                     This may correspond to a bug where undo does not update the selection. \
11508                     If this is occurring, please add details to \
11509                     https://github.com/zed-industries/zed/issues/22692"
11510                );
11511            }
11512            self.request_autoscroll(Autoscroll::fit(), cx);
11513            self.unmark_text(window, cx);
11514            self.refresh_inline_completion(true, false, window, cx);
11515            cx.emit(EditorEvent::Edited { transaction_id });
11516            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11517        }
11518    }
11519
11520    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11521        if self.read_only(cx) {
11522            return;
11523        }
11524
11525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11526
11527        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11528            if let Some((_, Some(selections))) =
11529                self.selection_history.transaction(transaction_id).cloned()
11530            {
11531                self.change_selections(None, window, cx, |s| {
11532                    s.select_anchors(selections.to_vec());
11533                });
11534            } else {
11535                log::error!(
11536                    "No entry in selection_history found for redo. \
11537                     This may correspond to a bug where undo does not update the selection. \
11538                     If this is occurring, please add details to \
11539                     https://github.com/zed-industries/zed/issues/22692"
11540                );
11541            }
11542            self.request_autoscroll(Autoscroll::fit(), cx);
11543            self.unmark_text(window, cx);
11544            self.refresh_inline_completion(true, false, window, cx);
11545            cx.emit(EditorEvent::Edited { transaction_id });
11546        }
11547    }
11548
11549    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11550        self.buffer
11551            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11552    }
11553
11554    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11555        self.buffer
11556            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11557    }
11558
11559    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11560        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11561        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11562            s.move_with(|map, selection| {
11563                let cursor = if selection.is_empty() {
11564                    movement::left(map, selection.start)
11565                } else {
11566                    selection.start
11567                };
11568                selection.collapse_to(cursor, SelectionGoal::None);
11569            });
11570        })
11571    }
11572
11573    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11574        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11575        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11576            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11577        })
11578    }
11579
11580    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11581        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11582        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11583            s.move_with(|map, selection| {
11584                let cursor = if selection.is_empty() {
11585                    movement::right(map, selection.end)
11586                } else {
11587                    selection.end
11588                };
11589                selection.collapse_to(cursor, SelectionGoal::None)
11590            });
11591        })
11592    }
11593
11594    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11595        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11596        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11597            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11598        })
11599    }
11600
11601    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11602        if self.take_rename(true, window, cx).is_some() {
11603            return;
11604        }
11605
11606        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11607            cx.propagate();
11608            return;
11609        }
11610
11611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11612
11613        let text_layout_details = &self.text_layout_details(window);
11614        let selection_count = self.selections.count();
11615        let first_selection = self.selections.first_anchor();
11616
11617        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11618            s.move_with(|map, selection| {
11619                if !selection.is_empty() {
11620                    selection.goal = SelectionGoal::None;
11621                }
11622                let (cursor, goal) = movement::up(
11623                    map,
11624                    selection.start,
11625                    selection.goal,
11626                    false,
11627                    text_layout_details,
11628                );
11629                selection.collapse_to(cursor, goal);
11630            });
11631        });
11632
11633        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11634        {
11635            cx.propagate();
11636        }
11637    }
11638
11639    pub fn move_up_by_lines(
11640        &mut self,
11641        action: &MoveUpByLines,
11642        window: &mut Window,
11643        cx: &mut Context<Self>,
11644    ) {
11645        if self.take_rename(true, window, cx).is_some() {
11646            return;
11647        }
11648
11649        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11650            cx.propagate();
11651            return;
11652        }
11653
11654        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11655
11656        let text_layout_details = &self.text_layout_details(window);
11657
11658        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11659            s.move_with(|map, selection| {
11660                if !selection.is_empty() {
11661                    selection.goal = SelectionGoal::None;
11662                }
11663                let (cursor, goal) = movement::up_by_rows(
11664                    map,
11665                    selection.start,
11666                    action.lines,
11667                    selection.goal,
11668                    false,
11669                    text_layout_details,
11670                );
11671                selection.collapse_to(cursor, goal);
11672            });
11673        })
11674    }
11675
11676    pub fn move_down_by_lines(
11677        &mut self,
11678        action: &MoveDownByLines,
11679        window: &mut Window,
11680        cx: &mut Context<Self>,
11681    ) {
11682        if self.take_rename(true, window, cx).is_some() {
11683            return;
11684        }
11685
11686        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11687            cx.propagate();
11688            return;
11689        }
11690
11691        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11692
11693        let text_layout_details = &self.text_layout_details(window);
11694
11695        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11696            s.move_with(|map, selection| {
11697                if !selection.is_empty() {
11698                    selection.goal = SelectionGoal::None;
11699                }
11700                let (cursor, goal) = movement::down_by_rows(
11701                    map,
11702                    selection.start,
11703                    action.lines,
11704                    selection.goal,
11705                    false,
11706                    text_layout_details,
11707                );
11708                selection.collapse_to(cursor, goal);
11709            });
11710        })
11711    }
11712
11713    pub fn select_down_by_lines(
11714        &mut self,
11715        action: &SelectDownByLines,
11716        window: &mut Window,
11717        cx: &mut Context<Self>,
11718    ) {
11719        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11720        let text_layout_details = &self.text_layout_details(window);
11721        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11722            s.move_heads_with(|map, head, goal| {
11723                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11724            })
11725        })
11726    }
11727
11728    pub fn select_up_by_lines(
11729        &mut self,
11730        action: &SelectUpByLines,
11731        window: &mut Window,
11732        cx: &mut Context<Self>,
11733    ) {
11734        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11735        let text_layout_details = &self.text_layout_details(window);
11736        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11737            s.move_heads_with(|map, head, goal| {
11738                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11739            })
11740        })
11741    }
11742
11743    pub fn select_page_up(
11744        &mut self,
11745        _: &SelectPageUp,
11746        window: &mut Window,
11747        cx: &mut Context<Self>,
11748    ) {
11749        let Some(row_count) = self.visible_row_count() else {
11750            return;
11751        };
11752
11753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11754
11755        let text_layout_details = &self.text_layout_details(window);
11756
11757        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11758            s.move_heads_with(|map, head, goal| {
11759                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11760            })
11761        })
11762    }
11763
11764    pub fn move_page_up(
11765        &mut self,
11766        action: &MovePageUp,
11767        window: &mut Window,
11768        cx: &mut Context<Self>,
11769    ) {
11770        if self.take_rename(true, window, cx).is_some() {
11771            return;
11772        }
11773
11774        if self
11775            .context_menu
11776            .borrow_mut()
11777            .as_mut()
11778            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11779            .unwrap_or(false)
11780        {
11781            return;
11782        }
11783
11784        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11785            cx.propagate();
11786            return;
11787        }
11788
11789        let Some(row_count) = self.visible_row_count() else {
11790            return;
11791        };
11792
11793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11794
11795        let autoscroll = if action.center_cursor {
11796            Autoscroll::center()
11797        } else {
11798            Autoscroll::fit()
11799        };
11800
11801        let text_layout_details = &self.text_layout_details(window);
11802
11803        self.change_selections(Some(autoscroll), window, cx, |s| {
11804            s.move_with(|map, selection| {
11805                if !selection.is_empty() {
11806                    selection.goal = SelectionGoal::None;
11807                }
11808                let (cursor, goal) = movement::up_by_rows(
11809                    map,
11810                    selection.end,
11811                    row_count,
11812                    selection.goal,
11813                    false,
11814                    text_layout_details,
11815                );
11816                selection.collapse_to(cursor, goal);
11817            });
11818        });
11819    }
11820
11821    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11822        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11823        let text_layout_details = &self.text_layout_details(window);
11824        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11825            s.move_heads_with(|map, head, goal| {
11826                movement::up(map, head, goal, false, text_layout_details)
11827            })
11828        })
11829    }
11830
11831    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11832        self.take_rename(true, window, cx);
11833
11834        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11835            cx.propagate();
11836            return;
11837        }
11838
11839        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11840
11841        let text_layout_details = &self.text_layout_details(window);
11842        let selection_count = self.selections.count();
11843        let first_selection = self.selections.first_anchor();
11844
11845        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11846            s.move_with(|map, selection| {
11847                if !selection.is_empty() {
11848                    selection.goal = SelectionGoal::None;
11849                }
11850                let (cursor, goal) = movement::down(
11851                    map,
11852                    selection.end,
11853                    selection.goal,
11854                    false,
11855                    text_layout_details,
11856                );
11857                selection.collapse_to(cursor, goal);
11858            });
11859        });
11860
11861        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11862        {
11863            cx.propagate();
11864        }
11865    }
11866
11867    pub fn select_page_down(
11868        &mut self,
11869        _: &SelectPageDown,
11870        window: &mut Window,
11871        cx: &mut Context<Self>,
11872    ) {
11873        let Some(row_count) = self.visible_row_count() else {
11874            return;
11875        };
11876
11877        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11878
11879        let text_layout_details = &self.text_layout_details(window);
11880
11881        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11882            s.move_heads_with(|map, head, goal| {
11883                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11884            })
11885        })
11886    }
11887
11888    pub fn move_page_down(
11889        &mut self,
11890        action: &MovePageDown,
11891        window: &mut Window,
11892        cx: &mut Context<Self>,
11893    ) {
11894        if self.take_rename(true, window, cx).is_some() {
11895            return;
11896        }
11897
11898        if self
11899            .context_menu
11900            .borrow_mut()
11901            .as_mut()
11902            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11903            .unwrap_or(false)
11904        {
11905            return;
11906        }
11907
11908        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11909            cx.propagate();
11910            return;
11911        }
11912
11913        let Some(row_count) = self.visible_row_count() else {
11914            return;
11915        };
11916
11917        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11918
11919        let autoscroll = if action.center_cursor {
11920            Autoscroll::center()
11921        } else {
11922            Autoscroll::fit()
11923        };
11924
11925        let text_layout_details = &self.text_layout_details(window);
11926        self.change_selections(Some(autoscroll), window, cx, |s| {
11927            s.move_with(|map, selection| {
11928                if !selection.is_empty() {
11929                    selection.goal = SelectionGoal::None;
11930                }
11931                let (cursor, goal) = movement::down_by_rows(
11932                    map,
11933                    selection.end,
11934                    row_count,
11935                    selection.goal,
11936                    false,
11937                    text_layout_details,
11938                );
11939                selection.collapse_to(cursor, goal);
11940            });
11941        });
11942    }
11943
11944    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11945        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11946        let text_layout_details = &self.text_layout_details(window);
11947        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11948            s.move_heads_with(|map, head, goal| {
11949                movement::down(map, head, goal, false, text_layout_details)
11950            })
11951        });
11952    }
11953
11954    pub fn context_menu_first(
11955        &mut self,
11956        _: &ContextMenuFirst,
11957        window: &mut Window,
11958        cx: &mut Context<Self>,
11959    ) {
11960        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11961            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11962        }
11963    }
11964
11965    pub fn context_menu_prev(
11966        &mut self,
11967        _: &ContextMenuPrevious,
11968        window: &mut Window,
11969        cx: &mut Context<Self>,
11970    ) {
11971        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11972            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11973        }
11974    }
11975
11976    pub fn context_menu_next(
11977        &mut self,
11978        _: &ContextMenuNext,
11979        window: &mut Window,
11980        cx: &mut Context<Self>,
11981    ) {
11982        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11983            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11984        }
11985    }
11986
11987    pub fn context_menu_last(
11988        &mut self,
11989        _: &ContextMenuLast,
11990        window: &mut Window,
11991        cx: &mut Context<Self>,
11992    ) {
11993        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11994            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11995        }
11996    }
11997
11998    pub fn move_to_previous_word_start(
11999        &mut self,
12000        _: &MoveToPreviousWordStart,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12005        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12006            s.move_cursors_with(|map, head, _| {
12007                (
12008                    movement::previous_word_start(map, head),
12009                    SelectionGoal::None,
12010                )
12011            });
12012        })
12013    }
12014
12015    pub fn move_to_previous_subword_start(
12016        &mut self,
12017        _: &MoveToPreviousSubwordStart,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12022        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12023            s.move_cursors_with(|map, head, _| {
12024                (
12025                    movement::previous_subword_start(map, head),
12026                    SelectionGoal::None,
12027                )
12028            });
12029        })
12030    }
12031
12032    pub fn select_to_previous_word_start(
12033        &mut self,
12034        _: &SelectToPreviousWordStart,
12035        window: &mut Window,
12036        cx: &mut Context<Self>,
12037    ) {
12038        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12039        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12040            s.move_heads_with(|map, head, _| {
12041                (
12042                    movement::previous_word_start(map, head),
12043                    SelectionGoal::None,
12044                )
12045            });
12046        })
12047    }
12048
12049    pub fn select_to_previous_subword_start(
12050        &mut self,
12051        _: &SelectToPreviousSubwordStart,
12052        window: &mut Window,
12053        cx: &mut Context<Self>,
12054    ) {
12055        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12056        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12057            s.move_heads_with(|map, head, _| {
12058                (
12059                    movement::previous_subword_start(map, head),
12060                    SelectionGoal::None,
12061                )
12062            });
12063        })
12064    }
12065
12066    pub fn delete_to_previous_word_start(
12067        &mut self,
12068        action: &DeleteToPreviousWordStart,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12073        self.transact(window, cx, |this, window, cx| {
12074            this.select_autoclose_pair(window, cx);
12075            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076                s.move_with(|map, selection| {
12077                    if selection.is_empty() {
12078                        let cursor = if action.ignore_newlines {
12079                            movement::previous_word_start(map, selection.head())
12080                        } else {
12081                            movement::previous_word_start_or_newline(map, selection.head())
12082                        };
12083                        selection.set_head(cursor, SelectionGoal::None);
12084                    }
12085                });
12086            });
12087            this.insert("", window, cx);
12088        });
12089    }
12090
12091    pub fn delete_to_previous_subword_start(
12092        &mut self,
12093        _: &DeleteToPreviousSubwordStart,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12098        self.transact(window, cx, |this, window, cx| {
12099            this.select_autoclose_pair(window, cx);
12100            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12101                s.move_with(|map, selection| {
12102                    if selection.is_empty() {
12103                        let cursor = movement::previous_subword_start(map, selection.head());
12104                        selection.set_head(cursor, SelectionGoal::None);
12105                    }
12106                });
12107            });
12108            this.insert("", window, cx);
12109        });
12110    }
12111
12112    pub fn move_to_next_word_end(
12113        &mut self,
12114        _: &MoveToNextWordEnd,
12115        window: &mut Window,
12116        cx: &mut Context<Self>,
12117    ) {
12118        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12119        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12120            s.move_cursors_with(|map, head, _| {
12121                (movement::next_word_end(map, head), SelectionGoal::None)
12122            });
12123        })
12124    }
12125
12126    pub fn move_to_next_subword_end(
12127        &mut self,
12128        _: &MoveToNextSubwordEnd,
12129        window: &mut Window,
12130        cx: &mut Context<Self>,
12131    ) {
12132        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12133        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12134            s.move_cursors_with(|map, head, _| {
12135                (movement::next_subword_end(map, head), SelectionGoal::None)
12136            });
12137        })
12138    }
12139
12140    pub fn select_to_next_word_end(
12141        &mut self,
12142        _: &SelectToNextWordEnd,
12143        window: &mut Window,
12144        cx: &mut Context<Self>,
12145    ) {
12146        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12147        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12148            s.move_heads_with(|map, head, _| {
12149                (movement::next_word_end(map, head), SelectionGoal::None)
12150            });
12151        })
12152    }
12153
12154    pub fn select_to_next_subword_end(
12155        &mut self,
12156        _: &SelectToNextSubwordEnd,
12157        window: &mut Window,
12158        cx: &mut Context<Self>,
12159    ) {
12160        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12161        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12162            s.move_heads_with(|map, head, _| {
12163                (movement::next_subword_end(map, head), SelectionGoal::None)
12164            });
12165        })
12166    }
12167
12168    pub fn delete_to_next_word_end(
12169        &mut self,
12170        action: &DeleteToNextWordEnd,
12171        window: &mut Window,
12172        cx: &mut Context<Self>,
12173    ) {
12174        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12175        self.transact(window, cx, |this, window, cx| {
12176            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12177                s.move_with(|map, selection| {
12178                    if selection.is_empty() {
12179                        let cursor = if action.ignore_newlines {
12180                            movement::next_word_end(map, selection.head())
12181                        } else {
12182                            movement::next_word_end_or_newline(map, selection.head())
12183                        };
12184                        selection.set_head(cursor, SelectionGoal::None);
12185                    }
12186                });
12187            });
12188            this.insert("", window, cx);
12189        });
12190    }
12191
12192    pub fn delete_to_next_subword_end(
12193        &mut self,
12194        _: &DeleteToNextSubwordEnd,
12195        window: &mut Window,
12196        cx: &mut Context<Self>,
12197    ) {
12198        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12199        self.transact(window, cx, |this, window, cx| {
12200            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12201                s.move_with(|map, selection| {
12202                    if selection.is_empty() {
12203                        let cursor = movement::next_subword_end(map, selection.head());
12204                        selection.set_head(cursor, SelectionGoal::None);
12205                    }
12206                });
12207            });
12208            this.insert("", window, cx);
12209        });
12210    }
12211
12212    pub fn move_to_beginning_of_line(
12213        &mut self,
12214        action: &MoveToBeginningOfLine,
12215        window: &mut Window,
12216        cx: &mut Context<Self>,
12217    ) {
12218        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12219        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12220            s.move_cursors_with(|map, head, _| {
12221                (
12222                    movement::indented_line_beginning(
12223                        map,
12224                        head,
12225                        action.stop_at_soft_wraps,
12226                        action.stop_at_indent,
12227                    ),
12228                    SelectionGoal::None,
12229                )
12230            });
12231        })
12232    }
12233
12234    pub fn select_to_beginning_of_line(
12235        &mut self,
12236        action: &SelectToBeginningOfLine,
12237        window: &mut Window,
12238        cx: &mut Context<Self>,
12239    ) {
12240        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12242            s.move_heads_with(|map, head, _| {
12243                (
12244                    movement::indented_line_beginning(
12245                        map,
12246                        head,
12247                        action.stop_at_soft_wraps,
12248                        action.stop_at_indent,
12249                    ),
12250                    SelectionGoal::None,
12251                )
12252            });
12253        });
12254    }
12255
12256    pub fn delete_to_beginning_of_line(
12257        &mut self,
12258        action: &DeleteToBeginningOfLine,
12259        window: &mut Window,
12260        cx: &mut Context<Self>,
12261    ) {
12262        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12263        self.transact(window, cx, |this, window, cx| {
12264            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12265                s.move_with(|_, selection| {
12266                    selection.reversed = true;
12267                });
12268            });
12269
12270            this.select_to_beginning_of_line(
12271                &SelectToBeginningOfLine {
12272                    stop_at_soft_wraps: false,
12273                    stop_at_indent: action.stop_at_indent,
12274                },
12275                window,
12276                cx,
12277            );
12278            this.backspace(&Backspace, window, cx);
12279        });
12280    }
12281
12282    pub fn move_to_end_of_line(
12283        &mut self,
12284        action: &MoveToEndOfLine,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12289        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12290            s.move_cursors_with(|map, head, _| {
12291                (
12292                    movement::line_end(map, head, action.stop_at_soft_wraps),
12293                    SelectionGoal::None,
12294                )
12295            });
12296        })
12297    }
12298
12299    pub fn select_to_end_of_line(
12300        &mut self,
12301        action: &SelectToEndOfLine,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12306        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12307            s.move_heads_with(|map, head, _| {
12308                (
12309                    movement::line_end(map, head, action.stop_at_soft_wraps),
12310                    SelectionGoal::None,
12311                )
12312            });
12313        })
12314    }
12315
12316    pub fn delete_to_end_of_line(
12317        &mut self,
12318        _: &DeleteToEndOfLine,
12319        window: &mut Window,
12320        cx: &mut Context<Self>,
12321    ) {
12322        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12323        self.transact(window, cx, |this, window, cx| {
12324            this.select_to_end_of_line(
12325                &SelectToEndOfLine {
12326                    stop_at_soft_wraps: false,
12327                },
12328                window,
12329                cx,
12330            );
12331            this.delete(&Delete, window, cx);
12332        });
12333    }
12334
12335    pub fn cut_to_end_of_line(
12336        &mut self,
12337        _: &CutToEndOfLine,
12338        window: &mut Window,
12339        cx: &mut Context<Self>,
12340    ) {
12341        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12342        self.transact(window, cx, |this, window, cx| {
12343            this.select_to_end_of_line(
12344                &SelectToEndOfLine {
12345                    stop_at_soft_wraps: false,
12346                },
12347                window,
12348                cx,
12349            );
12350            this.cut(&Cut, window, cx);
12351        });
12352    }
12353
12354    pub fn move_to_start_of_paragraph(
12355        &mut self,
12356        _: &MoveToStartOfParagraph,
12357        window: &mut Window,
12358        cx: &mut Context<Self>,
12359    ) {
12360        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12361            cx.propagate();
12362            return;
12363        }
12364        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12365        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12366            s.move_with(|map, selection| {
12367                selection.collapse_to(
12368                    movement::start_of_paragraph(map, selection.head(), 1),
12369                    SelectionGoal::None,
12370                )
12371            });
12372        })
12373    }
12374
12375    pub fn move_to_end_of_paragraph(
12376        &mut self,
12377        _: &MoveToEndOfParagraph,
12378        window: &mut Window,
12379        cx: &mut Context<Self>,
12380    ) {
12381        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12382            cx.propagate();
12383            return;
12384        }
12385        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12387            s.move_with(|map, selection| {
12388                selection.collapse_to(
12389                    movement::end_of_paragraph(map, selection.head(), 1),
12390                    SelectionGoal::None,
12391                )
12392            });
12393        })
12394    }
12395
12396    pub fn select_to_start_of_paragraph(
12397        &mut self,
12398        _: &SelectToStartOfParagraph,
12399        window: &mut Window,
12400        cx: &mut Context<Self>,
12401    ) {
12402        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12403            cx.propagate();
12404            return;
12405        }
12406        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12407        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12408            s.move_heads_with(|map, head, _| {
12409                (
12410                    movement::start_of_paragraph(map, head, 1),
12411                    SelectionGoal::None,
12412                )
12413            });
12414        })
12415    }
12416
12417    pub fn select_to_end_of_paragraph(
12418        &mut self,
12419        _: &SelectToEndOfParagraph,
12420        window: &mut Window,
12421        cx: &mut Context<Self>,
12422    ) {
12423        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12424            cx.propagate();
12425            return;
12426        }
12427        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12428        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12429            s.move_heads_with(|map, head, _| {
12430                (
12431                    movement::end_of_paragraph(map, head, 1),
12432                    SelectionGoal::None,
12433                )
12434            });
12435        })
12436    }
12437
12438    pub fn move_to_start_of_excerpt(
12439        &mut self,
12440        _: &MoveToStartOfExcerpt,
12441        window: &mut Window,
12442        cx: &mut Context<Self>,
12443    ) {
12444        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12445            cx.propagate();
12446            return;
12447        }
12448        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12449        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12450            s.move_with(|map, selection| {
12451                selection.collapse_to(
12452                    movement::start_of_excerpt(
12453                        map,
12454                        selection.head(),
12455                        workspace::searchable::Direction::Prev,
12456                    ),
12457                    SelectionGoal::None,
12458                )
12459            });
12460        })
12461    }
12462
12463    pub fn move_to_start_of_next_excerpt(
12464        &mut self,
12465        _: &MoveToStartOfNextExcerpt,
12466        window: &mut Window,
12467        cx: &mut Context<Self>,
12468    ) {
12469        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12470            cx.propagate();
12471            return;
12472        }
12473
12474        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12475            s.move_with(|map, selection| {
12476                selection.collapse_to(
12477                    movement::start_of_excerpt(
12478                        map,
12479                        selection.head(),
12480                        workspace::searchable::Direction::Next,
12481                    ),
12482                    SelectionGoal::None,
12483                )
12484            });
12485        })
12486    }
12487
12488    pub fn move_to_end_of_excerpt(
12489        &mut self,
12490        _: &MoveToEndOfExcerpt,
12491        window: &mut Window,
12492        cx: &mut Context<Self>,
12493    ) {
12494        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12495            cx.propagate();
12496            return;
12497        }
12498        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12499        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12500            s.move_with(|map, selection| {
12501                selection.collapse_to(
12502                    movement::end_of_excerpt(
12503                        map,
12504                        selection.head(),
12505                        workspace::searchable::Direction::Next,
12506                    ),
12507                    SelectionGoal::None,
12508                )
12509            });
12510        })
12511    }
12512
12513    pub fn move_to_end_of_previous_excerpt(
12514        &mut self,
12515        _: &MoveToEndOfPreviousExcerpt,
12516        window: &mut Window,
12517        cx: &mut Context<Self>,
12518    ) {
12519        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12520            cx.propagate();
12521            return;
12522        }
12523        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12524        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12525            s.move_with(|map, selection| {
12526                selection.collapse_to(
12527                    movement::end_of_excerpt(
12528                        map,
12529                        selection.head(),
12530                        workspace::searchable::Direction::Prev,
12531                    ),
12532                    SelectionGoal::None,
12533                )
12534            });
12535        })
12536    }
12537
12538    pub fn select_to_start_of_excerpt(
12539        &mut self,
12540        _: &SelectToStartOfExcerpt,
12541        window: &mut Window,
12542        cx: &mut Context<Self>,
12543    ) {
12544        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12545            cx.propagate();
12546            return;
12547        }
12548        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12549        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12550            s.move_heads_with(|map, head, _| {
12551                (
12552                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12553                    SelectionGoal::None,
12554                )
12555            });
12556        })
12557    }
12558
12559    pub fn select_to_start_of_next_excerpt(
12560        &mut self,
12561        _: &SelectToStartOfNextExcerpt,
12562        window: &mut Window,
12563        cx: &mut Context<Self>,
12564    ) {
12565        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12566            cx.propagate();
12567            return;
12568        }
12569        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12570        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12571            s.move_heads_with(|map, head, _| {
12572                (
12573                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12574                    SelectionGoal::None,
12575                )
12576            });
12577        })
12578    }
12579
12580    pub fn select_to_end_of_excerpt(
12581        &mut self,
12582        _: &SelectToEndOfExcerpt,
12583        window: &mut Window,
12584        cx: &mut Context<Self>,
12585    ) {
12586        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12587            cx.propagate();
12588            return;
12589        }
12590        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12591        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12592            s.move_heads_with(|map, head, _| {
12593                (
12594                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12595                    SelectionGoal::None,
12596                )
12597            });
12598        })
12599    }
12600
12601    pub fn select_to_end_of_previous_excerpt(
12602        &mut self,
12603        _: &SelectToEndOfPreviousExcerpt,
12604        window: &mut Window,
12605        cx: &mut Context<Self>,
12606    ) {
12607        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12608            cx.propagate();
12609            return;
12610        }
12611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12612        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12613            s.move_heads_with(|map, head, _| {
12614                (
12615                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12616                    SelectionGoal::None,
12617                )
12618            });
12619        })
12620    }
12621
12622    pub fn move_to_beginning(
12623        &mut self,
12624        _: &MoveToBeginning,
12625        window: &mut Window,
12626        cx: &mut Context<Self>,
12627    ) {
12628        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12629            cx.propagate();
12630            return;
12631        }
12632        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12633        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12634            s.select_ranges(vec![0..0]);
12635        });
12636    }
12637
12638    pub fn select_to_beginning(
12639        &mut self,
12640        _: &SelectToBeginning,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        let mut selection = self.selections.last::<Point>(cx);
12645        selection.set_head(Point::zero(), SelectionGoal::None);
12646        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12647        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12648            s.select(vec![selection]);
12649        });
12650    }
12651
12652    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12653        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12654            cx.propagate();
12655            return;
12656        }
12657        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12658        let cursor = self.buffer.read(cx).read(cx).len();
12659        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12660            s.select_ranges(vec![cursor..cursor])
12661        });
12662    }
12663
12664    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12665        self.nav_history = nav_history;
12666    }
12667
12668    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12669        self.nav_history.as_ref()
12670    }
12671
12672    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12673        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12674    }
12675
12676    fn push_to_nav_history(
12677        &mut self,
12678        cursor_anchor: Anchor,
12679        new_position: Option<Point>,
12680        is_deactivate: bool,
12681        cx: &mut Context<Self>,
12682    ) {
12683        if let Some(nav_history) = self.nav_history.as_mut() {
12684            let buffer = self.buffer.read(cx).read(cx);
12685            let cursor_position = cursor_anchor.to_point(&buffer);
12686            let scroll_state = self.scroll_manager.anchor();
12687            let scroll_top_row = scroll_state.top_row(&buffer);
12688            drop(buffer);
12689
12690            if let Some(new_position) = new_position {
12691                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12692                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12693                    return;
12694                }
12695            }
12696
12697            nav_history.push(
12698                Some(NavigationData {
12699                    cursor_anchor,
12700                    cursor_position,
12701                    scroll_anchor: scroll_state,
12702                    scroll_top_row,
12703                }),
12704                cx,
12705            );
12706            cx.emit(EditorEvent::PushedToNavHistory {
12707                anchor: cursor_anchor,
12708                is_deactivate,
12709            })
12710        }
12711    }
12712
12713    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12714        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12715        let buffer = self.buffer.read(cx).snapshot(cx);
12716        let mut selection = self.selections.first::<usize>(cx);
12717        selection.set_head(buffer.len(), SelectionGoal::None);
12718        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12719            s.select(vec![selection]);
12720        });
12721    }
12722
12723    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12724        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12725        let end = self.buffer.read(cx).read(cx).len();
12726        self.change_selections(None, window, cx, |s| {
12727            s.select_ranges(vec![0..end]);
12728        });
12729    }
12730
12731    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12732        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12733        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12734        let mut selections = self.selections.all::<Point>(cx);
12735        let max_point = display_map.buffer_snapshot.max_point();
12736        for selection in &mut selections {
12737            let rows = selection.spanned_rows(true, &display_map);
12738            selection.start = Point::new(rows.start.0, 0);
12739            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12740            selection.reversed = false;
12741        }
12742        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12743            s.select(selections);
12744        });
12745    }
12746
12747    pub fn split_selection_into_lines(
12748        &mut self,
12749        _: &SplitSelectionIntoLines,
12750        window: &mut Window,
12751        cx: &mut Context<Self>,
12752    ) {
12753        let selections = self
12754            .selections
12755            .all::<Point>(cx)
12756            .into_iter()
12757            .map(|selection| selection.start..selection.end)
12758            .collect::<Vec<_>>();
12759        self.unfold_ranges(&selections, true, true, cx);
12760
12761        let mut new_selection_ranges = Vec::new();
12762        {
12763            let buffer = self.buffer.read(cx).read(cx);
12764            for selection in selections {
12765                for row in selection.start.row..selection.end.row {
12766                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12767                    new_selection_ranges.push(cursor..cursor);
12768                }
12769
12770                let is_multiline_selection = selection.start.row != selection.end.row;
12771                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12772                // so this action feels more ergonomic when paired with other selection operations
12773                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12774                if !should_skip_last {
12775                    new_selection_ranges.push(selection.end..selection.end);
12776                }
12777            }
12778        }
12779        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12780            s.select_ranges(new_selection_ranges);
12781        });
12782    }
12783
12784    pub fn add_selection_above(
12785        &mut self,
12786        _: &AddSelectionAbove,
12787        window: &mut Window,
12788        cx: &mut Context<Self>,
12789    ) {
12790        self.add_selection(true, window, cx);
12791    }
12792
12793    pub fn add_selection_below(
12794        &mut self,
12795        _: &AddSelectionBelow,
12796        window: &mut Window,
12797        cx: &mut Context<Self>,
12798    ) {
12799        self.add_selection(false, window, cx);
12800    }
12801
12802    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12803        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12804
12805        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12806        let all_selections = self.selections.all::<Point>(cx);
12807        let text_layout_details = self.text_layout_details(window);
12808
12809        let (mut columnar_selections, new_selections_to_columnarize) = {
12810            if let Some(state) = self.add_selections_state.as_ref() {
12811                let columnar_selection_ids: HashSet<_> = state
12812                    .groups
12813                    .iter()
12814                    .flat_map(|group| group.stack.iter())
12815                    .copied()
12816                    .collect();
12817
12818                all_selections
12819                    .into_iter()
12820                    .partition(|s| columnar_selection_ids.contains(&s.id))
12821            } else {
12822                (Vec::new(), all_selections)
12823            }
12824        };
12825
12826        let mut state = self
12827            .add_selections_state
12828            .take()
12829            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12830
12831        for selection in new_selections_to_columnarize {
12832            let range = selection.display_range(&display_map).sorted();
12833            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12834            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12835            let positions = start_x.min(end_x)..start_x.max(end_x);
12836            let mut stack = Vec::new();
12837            for row in range.start.row().0..=range.end.row().0 {
12838                if let Some(selection) = self.selections.build_columnar_selection(
12839                    &display_map,
12840                    DisplayRow(row),
12841                    &positions,
12842                    selection.reversed,
12843                    &text_layout_details,
12844                ) {
12845                    stack.push(selection.id);
12846                    columnar_selections.push(selection);
12847                }
12848            }
12849            if !stack.is_empty() {
12850                if above {
12851                    stack.reverse();
12852                }
12853                state.groups.push(AddSelectionsGroup { above, stack });
12854            }
12855        }
12856
12857        let mut final_selections = Vec::new();
12858        let end_row = if above {
12859            DisplayRow(0)
12860        } else {
12861            display_map.max_point().row()
12862        };
12863
12864        let mut last_added_item_per_group = HashMap::default();
12865        for group in state.groups.iter_mut() {
12866            if let Some(last_id) = group.stack.last() {
12867                last_added_item_per_group.insert(*last_id, group);
12868            }
12869        }
12870
12871        for selection in columnar_selections {
12872            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12873                if above == group.above {
12874                    let range = selection.display_range(&display_map).sorted();
12875                    debug_assert_eq!(range.start.row(), range.end.row());
12876                    let mut row = range.start.row();
12877                    let positions =
12878                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12879                            px(start)..px(end)
12880                        } else {
12881                            let start_x =
12882                                display_map.x_for_display_point(range.start, &text_layout_details);
12883                            let end_x =
12884                                display_map.x_for_display_point(range.end, &text_layout_details);
12885                            start_x.min(end_x)..start_x.max(end_x)
12886                        };
12887
12888                    let mut maybe_new_selection = None;
12889                    while row != end_row {
12890                        if above {
12891                            row.0 -= 1;
12892                        } else {
12893                            row.0 += 1;
12894                        }
12895                        if let Some(new_selection) = self.selections.build_columnar_selection(
12896                            &display_map,
12897                            row,
12898                            &positions,
12899                            selection.reversed,
12900                            &text_layout_details,
12901                        ) {
12902                            maybe_new_selection = Some(new_selection);
12903                            break;
12904                        }
12905                    }
12906
12907                    if let Some(new_selection) = maybe_new_selection {
12908                        group.stack.push(new_selection.id);
12909                        if above {
12910                            final_selections.push(new_selection);
12911                            final_selections.push(selection);
12912                        } else {
12913                            final_selections.push(selection);
12914                            final_selections.push(new_selection);
12915                        }
12916                    } else {
12917                        final_selections.push(selection);
12918                    }
12919                } else {
12920                    group.stack.pop();
12921                }
12922            } else {
12923                final_selections.push(selection);
12924            }
12925        }
12926
12927        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12928            s.select(final_selections);
12929        });
12930
12931        let final_selection_ids: HashSet<_> = self
12932            .selections
12933            .all::<Point>(cx)
12934            .iter()
12935            .map(|s| s.id)
12936            .collect();
12937        state.groups.retain_mut(|group| {
12938            // selections might get merged above so we remove invalid items from stacks
12939            group.stack.retain(|id| final_selection_ids.contains(id));
12940
12941            // single selection in stack can be treated as initial state
12942            group.stack.len() > 1
12943        });
12944
12945        if !state.groups.is_empty() {
12946            self.add_selections_state = Some(state);
12947        }
12948    }
12949
12950    fn select_match_ranges(
12951        &mut self,
12952        range: Range<usize>,
12953        reversed: bool,
12954        replace_newest: bool,
12955        auto_scroll: Option<Autoscroll>,
12956        window: &mut Window,
12957        cx: &mut Context<Editor>,
12958    ) {
12959        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12960        self.change_selections(auto_scroll, window, cx, |s| {
12961            if replace_newest {
12962                s.delete(s.newest_anchor().id);
12963            }
12964            if reversed {
12965                s.insert_range(range.end..range.start);
12966            } else {
12967                s.insert_range(range);
12968            }
12969        });
12970    }
12971
12972    pub fn select_next_match_internal(
12973        &mut self,
12974        display_map: &DisplaySnapshot,
12975        replace_newest: bool,
12976        autoscroll: Option<Autoscroll>,
12977        window: &mut Window,
12978        cx: &mut Context<Self>,
12979    ) -> Result<()> {
12980        let buffer = &display_map.buffer_snapshot;
12981        let mut selections = self.selections.all::<usize>(cx);
12982        if let Some(mut select_next_state) = self.select_next_state.take() {
12983            let query = &select_next_state.query;
12984            if !select_next_state.done {
12985                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12986                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12987                let mut next_selected_range = None;
12988
12989                let bytes_after_last_selection =
12990                    buffer.bytes_in_range(last_selection.end..buffer.len());
12991                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12992                let query_matches = query
12993                    .stream_find_iter(bytes_after_last_selection)
12994                    .map(|result| (last_selection.end, result))
12995                    .chain(
12996                        query
12997                            .stream_find_iter(bytes_before_first_selection)
12998                            .map(|result| (0, result)),
12999                    );
13000
13001                for (start_offset, query_match) in query_matches {
13002                    let query_match = query_match.unwrap(); // can only fail due to I/O
13003                    let offset_range =
13004                        start_offset + query_match.start()..start_offset + query_match.end();
13005                    let display_range = offset_range.start.to_display_point(display_map)
13006                        ..offset_range.end.to_display_point(display_map);
13007
13008                    if !select_next_state.wordwise
13009                        || (!movement::is_inside_word(display_map, display_range.start)
13010                            && !movement::is_inside_word(display_map, display_range.end))
13011                    {
13012                        // TODO: This is n^2, because we might check all the selections
13013                        if !selections
13014                            .iter()
13015                            .any(|selection| selection.range().overlaps(&offset_range))
13016                        {
13017                            next_selected_range = Some(offset_range);
13018                            break;
13019                        }
13020                    }
13021                }
13022
13023                if let Some(next_selected_range) = next_selected_range {
13024                    self.select_match_ranges(
13025                        next_selected_range,
13026                        last_selection.reversed,
13027                        replace_newest,
13028                        autoscroll,
13029                        window,
13030                        cx,
13031                    );
13032                } else {
13033                    select_next_state.done = true;
13034                }
13035            }
13036
13037            self.select_next_state = Some(select_next_state);
13038        } else {
13039            let mut only_carets = true;
13040            let mut same_text_selected = true;
13041            let mut selected_text = None;
13042
13043            let mut selections_iter = selections.iter().peekable();
13044            while let Some(selection) = selections_iter.next() {
13045                if selection.start != selection.end {
13046                    only_carets = false;
13047                }
13048
13049                if same_text_selected {
13050                    if selected_text.is_none() {
13051                        selected_text =
13052                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13053                    }
13054
13055                    if let Some(next_selection) = selections_iter.peek() {
13056                        if next_selection.range().len() == selection.range().len() {
13057                            let next_selected_text = buffer
13058                                .text_for_range(next_selection.range())
13059                                .collect::<String>();
13060                            if Some(next_selected_text) != selected_text {
13061                                same_text_selected = false;
13062                                selected_text = None;
13063                            }
13064                        } else {
13065                            same_text_selected = false;
13066                            selected_text = None;
13067                        }
13068                    }
13069                }
13070            }
13071
13072            if only_carets {
13073                for selection in &mut selections {
13074                    let word_range = movement::surrounding_word(
13075                        display_map,
13076                        selection.start.to_display_point(display_map),
13077                    );
13078                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13079                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13080                    selection.goal = SelectionGoal::None;
13081                    selection.reversed = false;
13082                    self.select_match_ranges(
13083                        selection.start..selection.end,
13084                        selection.reversed,
13085                        replace_newest,
13086                        autoscroll,
13087                        window,
13088                        cx,
13089                    );
13090                }
13091
13092                if selections.len() == 1 {
13093                    let selection = selections
13094                        .last()
13095                        .expect("ensured that there's only one selection");
13096                    let query = buffer
13097                        .text_for_range(selection.start..selection.end)
13098                        .collect::<String>();
13099                    let is_empty = query.is_empty();
13100                    let select_state = SelectNextState {
13101                        query: AhoCorasick::new(&[query])?,
13102                        wordwise: true,
13103                        done: is_empty,
13104                    };
13105                    self.select_next_state = Some(select_state);
13106                } else {
13107                    self.select_next_state = None;
13108                }
13109            } else if let Some(selected_text) = selected_text {
13110                self.select_next_state = Some(SelectNextState {
13111                    query: AhoCorasick::new(&[selected_text])?,
13112                    wordwise: false,
13113                    done: false,
13114                });
13115                self.select_next_match_internal(
13116                    display_map,
13117                    replace_newest,
13118                    autoscroll,
13119                    window,
13120                    cx,
13121                )?;
13122            }
13123        }
13124        Ok(())
13125    }
13126
13127    pub fn select_all_matches(
13128        &mut self,
13129        _action: &SelectAllMatches,
13130        window: &mut Window,
13131        cx: &mut Context<Self>,
13132    ) -> Result<()> {
13133        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13134
13135        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13136
13137        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13138        let Some(select_next_state) = self.select_next_state.as_mut() else {
13139            return Ok(());
13140        };
13141        if select_next_state.done {
13142            return Ok(());
13143        }
13144
13145        let mut new_selections = Vec::new();
13146
13147        let reversed = self.selections.oldest::<usize>(cx).reversed;
13148        let buffer = &display_map.buffer_snapshot;
13149        let query_matches = select_next_state
13150            .query
13151            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13152
13153        for query_match in query_matches.into_iter() {
13154            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13155            let offset_range = if reversed {
13156                query_match.end()..query_match.start()
13157            } else {
13158                query_match.start()..query_match.end()
13159            };
13160            let display_range = offset_range.start.to_display_point(&display_map)
13161                ..offset_range.end.to_display_point(&display_map);
13162
13163            if !select_next_state.wordwise
13164                || (!movement::is_inside_word(&display_map, display_range.start)
13165                    && !movement::is_inside_word(&display_map, display_range.end))
13166            {
13167                new_selections.push(offset_range.start..offset_range.end);
13168            }
13169        }
13170
13171        select_next_state.done = true;
13172        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13173        self.change_selections(None, window, cx, |selections| {
13174            selections.select_ranges(new_selections)
13175        });
13176
13177        Ok(())
13178    }
13179
13180    pub fn select_next(
13181        &mut self,
13182        action: &SelectNext,
13183        window: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) -> Result<()> {
13186        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13188        self.select_next_match_internal(
13189            &display_map,
13190            action.replace_newest,
13191            Some(Autoscroll::newest()),
13192            window,
13193            cx,
13194        )?;
13195        Ok(())
13196    }
13197
13198    pub fn select_previous(
13199        &mut self,
13200        action: &SelectPrevious,
13201        window: &mut Window,
13202        cx: &mut Context<Self>,
13203    ) -> Result<()> {
13204        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13206        let buffer = &display_map.buffer_snapshot;
13207        let mut selections = self.selections.all::<usize>(cx);
13208        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13209            let query = &select_prev_state.query;
13210            if !select_prev_state.done {
13211                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13212                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13213                let mut next_selected_range = None;
13214                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13215                let bytes_before_last_selection =
13216                    buffer.reversed_bytes_in_range(0..last_selection.start);
13217                let bytes_after_first_selection =
13218                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13219                let query_matches = query
13220                    .stream_find_iter(bytes_before_last_selection)
13221                    .map(|result| (last_selection.start, result))
13222                    .chain(
13223                        query
13224                            .stream_find_iter(bytes_after_first_selection)
13225                            .map(|result| (buffer.len(), result)),
13226                    );
13227                for (end_offset, query_match) in query_matches {
13228                    let query_match = query_match.unwrap(); // can only fail due to I/O
13229                    let offset_range =
13230                        end_offset - query_match.end()..end_offset - query_match.start();
13231                    let display_range = offset_range.start.to_display_point(&display_map)
13232                        ..offset_range.end.to_display_point(&display_map);
13233
13234                    if !select_prev_state.wordwise
13235                        || (!movement::is_inside_word(&display_map, display_range.start)
13236                            && !movement::is_inside_word(&display_map, display_range.end))
13237                    {
13238                        next_selected_range = Some(offset_range);
13239                        break;
13240                    }
13241                }
13242
13243                if let Some(next_selected_range) = next_selected_range {
13244                    self.select_match_ranges(
13245                        next_selected_range,
13246                        last_selection.reversed,
13247                        action.replace_newest,
13248                        Some(Autoscroll::newest()),
13249                        window,
13250                        cx,
13251                    );
13252                } else {
13253                    select_prev_state.done = true;
13254                }
13255            }
13256
13257            self.select_prev_state = Some(select_prev_state);
13258        } else {
13259            let mut only_carets = true;
13260            let mut same_text_selected = true;
13261            let mut selected_text = None;
13262
13263            let mut selections_iter = selections.iter().peekable();
13264            while let Some(selection) = selections_iter.next() {
13265                if selection.start != selection.end {
13266                    only_carets = false;
13267                }
13268
13269                if same_text_selected {
13270                    if selected_text.is_none() {
13271                        selected_text =
13272                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13273                    }
13274
13275                    if let Some(next_selection) = selections_iter.peek() {
13276                        if next_selection.range().len() == selection.range().len() {
13277                            let next_selected_text = buffer
13278                                .text_for_range(next_selection.range())
13279                                .collect::<String>();
13280                            if Some(next_selected_text) != selected_text {
13281                                same_text_selected = false;
13282                                selected_text = None;
13283                            }
13284                        } else {
13285                            same_text_selected = false;
13286                            selected_text = None;
13287                        }
13288                    }
13289                }
13290            }
13291
13292            if only_carets {
13293                for selection in &mut selections {
13294                    let word_range = movement::surrounding_word(
13295                        &display_map,
13296                        selection.start.to_display_point(&display_map),
13297                    );
13298                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13299                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13300                    selection.goal = SelectionGoal::None;
13301                    selection.reversed = false;
13302                    self.select_match_ranges(
13303                        selection.start..selection.end,
13304                        selection.reversed,
13305                        action.replace_newest,
13306                        Some(Autoscroll::newest()),
13307                        window,
13308                        cx,
13309                    );
13310                }
13311                if selections.len() == 1 {
13312                    let selection = selections
13313                        .last()
13314                        .expect("ensured that there's only one selection");
13315                    let query = buffer
13316                        .text_for_range(selection.start..selection.end)
13317                        .collect::<String>();
13318                    let is_empty = query.is_empty();
13319                    let select_state = SelectNextState {
13320                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13321                        wordwise: true,
13322                        done: is_empty,
13323                    };
13324                    self.select_prev_state = Some(select_state);
13325                } else {
13326                    self.select_prev_state = None;
13327                }
13328            } else if let Some(selected_text) = selected_text {
13329                self.select_prev_state = Some(SelectNextState {
13330                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13331                    wordwise: false,
13332                    done: false,
13333                });
13334                self.select_previous(action, window, cx)?;
13335            }
13336        }
13337        Ok(())
13338    }
13339
13340    pub fn find_next_match(
13341        &mut self,
13342        _: &FindNextMatch,
13343        window: &mut Window,
13344        cx: &mut Context<Self>,
13345    ) -> Result<()> {
13346        let selections = self.selections.disjoint_anchors();
13347        match selections.first() {
13348            Some(first) if selections.len() >= 2 => {
13349                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13350                    s.select_ranges([first.range()]);
13351                });
13352            }
13353            _ => self.select_next(
13354                &SelectNext {
13355                    replace_newest: true,
13356                },
13357                window,
13358                cx,
13359            )?,
13360        }
13361        Ok(())
13362    }
13363
13364    pub fn find_previous_match(
13365        &mut self,
13366        _: &FindPreviousMatch,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) -> Result<()> {
13370        let selections = self.selections.disjoint_anchors();
13371        match selections.last() {
13372            Some(last) if selections.len() >= 2 => {
13373                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13374                    s.select_ranges([last.range()]);
13375                });
13376            }
13377            _ => self.select_previous(
13378                &SelectPrevious {
13379                    replace_newest: true,
13380                },
13381                window,
13382                cx,
13383            )?,
13384        }
13385        Ok(())
13386    }
13387
13388    pub fn toggle_comments(
13389        &mut self,
13390        action: &ToggleComments,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        if self.read_only(cx) {
13395            return;
13396        }
13397        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13398        let text_layout_details = &self.text_layout_details(window);
13399        self.transact(window, cx, |this, window, cx| {
13400            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13401            let mut edits = Vec::new();
13402            let mut selection_edit_ranges = Vec::new();
13403            let mut last_toggled_row = None;
13404            let snapshot = this.buffer.read(cx).read(cx);
13405            let empty_str: Arc<str> = Arc::default();
13406            let mut suffixes_inserted = Vec::new();
13407            let ignore_indent = action.ignore_indent;
13408
13409            fn comment_prefix_range(
13410                snapshot: &MultiBufferSnapshot,
13411                row: MultiBufferRow,
13412                comment_prefix: &str,
13413                comment_prefix_whitespace: &str,
13414                ignore_indent: bool,
13415            ) -> Range<Point> {
13416                let indent_size = if ignore_indent {
13417                    0
13418                } else {
13419                    snapshot.indent_size_for_line(row).len
13420                };
13421
13422                let start = Point::new(row.0, indent_size);
13423
13424                let mut line_bytes = snapshot
13425                    .bytes_in_range(start..snapshot.max_point())
13426                    .flatten()
13427                    .copied();
13428
13429                // If this line currently begins with the line comment prefix, then record
13430                // the range containing the prefix.
13431                if line_bytes
13432                    .by_ref()
13433                    .take(comment_prefix.len())
13434                    .eq(comment_prefix.bytes())
13435                {
13436                    // Include any whitespace that matches the comment prefix.
13437                    let matching_whitespace_len = line_bytes
13438                        .zip(comment_prefix_whitespace.bytes())
13439                        .take_while(|(a, b)| a == b)
13440                        .count() as u32;
13441                    let end = Point::new(
13442                        start.row,
13443                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13444                    );
13445                    start..end
13446                } else {
13447                    start..start
13448                }
13449            }
13450
13451            fn comment_suffix_range(
13452                snapshot: &MultiBufferSnapshot,
13453                row: MultiBufferRow,
13454                comment_suffix: &str,
13455                comment_suffix_has_leading_space: bool,
13456            ) -> Range<Point> {
13457                let end = Point::new(row.0, snapshot.line_len(row));
13458                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13459
13460                let mut line_end_bytes = snapshot
13461                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13462                    .flatten()
13463                    .copied();
13464
13465                let leading_space_len = if suffix_start_column > 0
13466                    && line_end_bytes.next() == Some(b' ')
13467                    && comment_suffix_has_leading_space
13468                {
13469                    1
13470                } else {
13471                    0
13472                };
13473
13474                // If this line currently begins with the line comment prefix, then record
13475                // the range containing the prefix.
13476                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13477                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13478                    start..end
13479                } else {
13480                    end..end
13481                }
13482            }
13483
13484            // TODO: Handle selections that cross excerpts
13485            for selection in &mut selections {
13486                let start_column = snapshot
13487                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13488                    .len;
13489                let language = if let Some(language) =
13490                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13491                {
13492                    language
13493                } else {
13494                    continue;
13495                };
13496
13497                selection_edit_ranges.clear();
13498
13499                // If multiple selections contain a given row, avoid processing that
13500                // row more than once.
13501                let mut start_row = MultiBufferRow(selection.start.row);
13502                if last_toggled_row == Some(start_row) {
13503                    start_row = start_row.next_row();
13504                }
13505                let end_row =
13506                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13507                        MultiBufferRow(selection.end.row - 1)
13508                    } else {
13509                        MultiBufferRow(selection.end.row)
13510                    };
13511                last_toggled_row = Some(end_row);
13512
13513                if start_row > end_row {
13514                    continue;
13515                }
13516
13517                // If the language has line comments, toggle those.
13518                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13519
13520                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13521                if ignore_indent {
13522                    full_comment_prefixes = full_comment_prefixes
13523                        .into_iter()
13524                        .map(|s| Arc::from(s.trim_end()))
13525                        .collect();
13526                }
13527
13528                if !full_comment_prefixes.is_empty() {
13529                    let first_prefix = full_comment_prefixes
13530                        .first()
13531                        .expect("prefixes is non-empty");
13532                    let prefix_trimmed_lengths = full_comment_prefixes
13533                        .iter()
13534                        .map(|p| p.trim_end_matches(' ').len())
13535                        .collect::<SmallVec<[usize; 4]>>();
13536
13537                    let mut all_selection_lines_are_comments = true;
13538
13539                    for row in start_row.0..=end_row.0 {
13540                        let row = MultiBufferRow(row);
13541                        if start_row < end_row && snapshot.is_line_blank(row) {
13542                            continue;
13543                        }
13544
13545                        let prefix_range = full_comment_prefixes
13546                            .iter()
13547                            .zip(prefix_trimmed_lengths.iter().copied())
13548                            .map(|(prefix, trimmed_prefix_len)| {
13549                                comment_prefix_range(
13550                                    snapshot.deref(),
13551                                    row,
13552                                    &prefix[..trimmed_prefix_len],
13553                                    &prefix[trimmed_prefix_len..],
13554                                    ignore_indent,
13555                                )
13556                            })
13557                            .max_by_key(|range| range.end.column - range.start.column)
13558                            .expect("prefixes is non-empty");
13559
13560                        if prefix_range.is_empty() {
13561                            all_selection_lines_are_comments = false;
13562                        }
13563
13564                        selection_edit_ranges.push(prefix_range);
13565                    }
13566
13567                    if all_selection_lines_are_comments {
13568                        edits.extend(
13569                            selection_edit_ranges
13570                                .iter()
13571                                .cloned()
13572                                .map(|range| (range, empty_str.clone())),
13573                        );
13574                    } else {
13575                        let min_column = selection_edit_ranges
13576                            .iter()
13577                            .map(|range| range.start.column)
13578                            .min()
13579                            .unwrap_or(0);
13580                        edits.extend(selection_edit_ranges.iter().map(|range| {
13581                            let position = Point::new(range.start.row, min_column);
13582                            (position..position, first_prefix.clone())
13583                        }));
13584                    }
13585                } else if let Some((full_comment_prefix, comment_suffix)) =
13586                    language.block_comment_delimiters()
13587                {
13588                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13589                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13590                    let prefix_range = comment_prefix_range(
13591                        snapshot.deref(),
13592                        start_row,
13593                        comment_prefix,
13594                        comment_prefix_whitespace,
13595                        ignore_indent,
13596                    );
13597                    let suffix_range = comment_suffix_range(
13598                        snapshot.deref(),
13599                        end_row,
13600                        comment_suffix.trim_start_matches(' '),
13601                        comment_suffix.starts_with(' '),
13602                    );
13603
13604                    if prefix_range.is_empty() || suffix_range.is_empty() {
13605                        edits.push((
13606                            prefix_range.start..prefix_range.start,
13607                            full_comment_prefix.clone(),
13608                        ));
13609                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13610                        suffixes_inserted.push((end_row, comment_suffix.len()));
13611                    } else {
13612                        edits.push((prefix_range, empty_str.clone()));
13613                        edits.push((suffix_range, empty_str.clone()));
13614                    }
13615                } else {
13616                    continue;
13617                }
13618            }
13619
13620            drop(snapshot);
13621            this.buffer.update(cx, |buffer, cx| {
13622                buffer.edit(edits, None, cx);
13623            });
13624
13625            // Adjust selections so that they end before any comment suffixes that
13626            // were inserted.
13627            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13628            let mut selections = this.selections.all::<Point>(cx);
13629            let snapshot = this.buffer.read(cx).read(cx);
13630            for selection in &mut selections {
13631                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13632                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13633                        Ordering::Less => {
13634                            suffixes_inserted.next();
13635                            continue;
13636                        }
13637                        Ordering::Greater => break,
13638                        Ordering::Equal => {
13639                            if selection.end.column == snapshot.line_len(row) {
13640                                if selection.is_empty() {
13641                                    selection.start.column -= suffix_len as u32;
13642                                }
13643                                selection.end.column -= suffix_len as u32;
13644                            }
13645                            break;
13646                        }
13647                    }
13648                }
13649            }
13650
13651            drop(snapshot);
13652            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13653                s.select(selections)
13654            });
13655
13656            let selections = this.selections.all::<Point>(cx);
13657            let selections_on_single_row = selections.windows(2).all(|selections| {
13658                selections[0].start.row == selections[1].start.row
13659                    && selections[0].end.row == selections[1].end.row
13660                    && selections[0].start.row == selections[0].end.row
13661            });
13662            let selections_selecting = selections
13663                .iter()
13664                .any(|selection| selection.start != selection.end);
13665            let advance_downwards = action.advance_downwards
13666                && selections_on_single_row
13667                && !selections_selecting
13668                && !matches!(this.mode, EditorMode::SingleLine { .. });
13669
13670            if advance_downwards {
13671                let snapshot = this.buffer.read(cx).snapshot(cx);
13672
13673                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13674                    s.move_cursors_with(|display_snapshot, display_point, _| {
13675                        let mut point = display_point.to_point(display_snapshot);
13676                        point.row += 1;
13677                        point = snapshot.clip_point(point, Bias::Left);
13678                        let display_point = point.to_display_point(display_snapshot);
13679                        let goal = SelectionGoal::HorizontalPosition(
13680                            display_snapshot
13681                                .x_for_display_point(display_point, text_layout_details)
13682                                .into(),
13683                        );
13684                        (display_point, goal)
13685                    })
13686                });
13687            }
13688        });
13689    }
13690
13691    pub fn select_enclosing_symbol(
13692        &mut self,
13693        _: &SelectEnclosingSymbol,
13694        window: &mut Window,
13695        cx: &mut Context<Self>,
13696    ) {
13697        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13698
13699        let buffer = self.buffer.read(cx).snapshot(cx);
13700        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13701
13702        fn update_selection(
13703            selection: &Selection<usize>,
13704            buffer_snap: &MultiBufferSnapshot,
13705        ) -> Option<Selection<usize>> {
13706            let cursor = selection.head();
13707            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13708            for symbol in symbols.iter().rev() {
13709                let start = symbol.range.start.to_offset(buffer_snap);
13710                let end = symbol.range.end.to_offset(buffer_snap);
13711                let new_range = start..end;
13712                if start < selection.start || end > selection.end {
13713                    return Some(Selection {
13714                        id: selection.id,
13715                        start: new_range.start,
13716                        end: new_range.end,
13717                        goal: SelectionGoal::None,
13718                        reversed: selection.reversed,
13719                    });
13720                }
13721            }
13722            None
13723        }
13724
13725        let mut selected_larger_symbol = false;
13726        let new_selections = old_selections
13727            .iter()
13728            .map(|selection| match update_selection(selection, &buffer) {
13729                Some(new_selection) => {
13730                    if new_selection.range() != selection.range() {
13731                        selected_larger_symbol = true;
13732                    }
13733                    new_selection
13734                }
13735                None => selection.clone(),
13736            })
13737            .collect::<Vec<_>>();
13738
13739        if selected_larger_symbol {
13740            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13741                s.select(new_selections);
13742            });
13743        }
13744    }
13745
13746    pub fn select_larger_syntax_node(
13747        &mut self,
13748        _: &SelectLargerSyntaxNode,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        let Some(visible_row_count) = self.visible_row_count() else {
13753            return;
13754        };
13755        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13756        if old_selections.is_empty() {
13757            return;
13758        }
13759
13760        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13761
13762        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13763        let buffer = self.buffer.read(cx).snapshot(cx);
13764
13765        let mut selected_larger_node = false;
13766        let mut new_selections = old_selections
13767            .iter()
13768            .map(|selection| {
13769                let old_range = selection.start..selection.end;
13770
13771                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13772                    // manually select word at selection
13773                    if ["string_content", "inline"].contains(&node.kind()) {
13774                        let word_range = {
13775                            let display_point = buffer
13776                                .offset_to_point(old_range.start)
13777                                .to_display_point(&display_map);
13778                            let Range { start, end } =
13779                                movement::surrounding_word(&display_map, display_point);
13780                            start.to_point(&display_map).to_offset(&buffer)
13781                                ..end.to_point(&display_map).to_offset(&buffer)
13782                        };
13783                        // ignore if word is already selected
13784                        if !word_range.is_empty() && old_range != word_range {
13785                            let last_word_range = {
13786                                let display_point = buffer
13787                                    .offset_to_point(old_range.end)
13788                                    .to_display_point(&display_map);
13789                                let Range { start, end } =
13790                                    movement::surrounding_word(&display_map, display_point);
13791                                start.to_point(&display_map).to_offset(&buffer)
13792                                    ..end.to_point(&display_map).to_offset(&buffer)
13793                            };
13794                            // only select word if start and end point belongs to same word
13795                            if word_range == last_word_range {
13796                                selected_larger_node = true;
13797                                return Selection {
13798                                    id: selection.id,
13799                                    start: word_range.start,
13800                                    end: word_range.end,
13801                                    goal: SelectionGoal::None,
13802                                    reversed: selection.reversed,
13803                                };
13804                            }
13805                        }
13806                    }
13807                }
13808
13809                let mut new_range = old_range.clone();
13810                while let Some((_node, containing_range)) =
13811                    buffer.syntax_ancestor(new_range.clone())
13812                {
13813                    new_range = match containing_range {
13814                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13815                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13816                    };
13817                    if !display_map.intersects_fold(new_range.start)
13818                        && !display_map.intersects_fold(new_range.end)
13819                    {
13820                        break;
13821                    }
13822                }
13823
13824                selected_larger_node |= new_range != old_range;
13825                Selection {
13826                    id: selection.id,
13827                    start: new_range.start,
13828                    end: new_range.end,
13829                    goal: SelectionGoal::None,
13830                    reversed: selection.reversed,
13831                }
13832            })
13833            .collect::<Vec<_>>();
13834
13835        if !selected_larger_node {
13836            return; // don't put this call in the history
13837        }
13838
13839        // scroll based on transformation done to the last selection created by the user
13840        let (last_old, last_new) = old_selections
13841            .last()
13842            .zip(new_selections.last().cloned())
13843            .expect("old_selections isn't empty");
13844
13845        // revert selection
13846        let is_selection_reversed = {
13847            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13848            new_selections.last_mut().expect("checked above").reversed =
13849                should_newest_selection_be_reversed;
13850            should_newest_selection_be_reversed
13851        };
13852
13853        if selected_larger_node {
13854            self.select_syntax_node_history.disable_clearing = true;
13855            self.change_selections(None, window, cx, |s| {
13856                s.select(new_selections.clone());
13857            });
13858            self.select_syntax_node_history.disable_clearing = false;
13859        }
13860
13861        let start_row = last_new.start.to_display_point(&display_map).row().0;
13862        let end_row = last_new.end.to_display_point(&display_map).row().0;
13863        let selection_height = end_row - start_row + 1;
13864        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13865
13866        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13867        let scroll_behavior = if fits_on_the_screen {
13868            self.request_autoscroll(Autoscroll::fit(), cx);
13869            SelectSyntaxNodeScrollBehavior::FitSelection
13870        } else if is_selection_reversed {
13871            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13872            SelectSyntaxNodeScrollBehavior::CursorTop
13873        } else {
13874            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13875            SelectSyntaxNodeScrollBehavior::CursorBottom
13876        };
13877
13878        self.select_syntax_node_history.push((
13879            old_selections,
13880            scroll_behavior,
13881            is_selection_reversed,
13882        ));
13883    }
13884
13885    pub fn select_smaller_syntax_node(
13886        &mut self,
13887        _: &SelectSmallerSyntaxNode,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13892
13893        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13894            self.select_syntax_node_history.pop()
13895        {
13896            if let Some(selection) = selections.last_mut() {
13897                selection.reversed = is_selection_reversed;
13898            }
13899
13900            self.select_syntax_node_history.disable_clearing = true;
13901            self.change_selections(None, window, cx, |s| {
13902                s.select(selections.to_vec());
13903            });
13904            self.select_syntax_node_history.disable_clearing = false;
13905
13906            match scroll_behavior {
13907                SelectSyntaxNodeScrollBehavior::CursorTop => {
13908                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13909                }
13910                SelectSyntaxNodeScrollBehavior::FitSelection => {
13911                    self.request_autoscroll(Autoscroll::fit(), cx);
13912                }
13913                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13914                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13915                }
13916            }
13917        }
13918    }
13919
13920    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13921        if !EditorSettings::get_global(cx).gutter.runnables {
13922            self.clear_tasks();
13923            return Task::ready(());
13924        }
13925        let project = self.project.as_ref().map(Entity::downgrade);
13926        let task_sources = self.lsp_task_sources(cx);
13927        let multi_buffer = self.buffer.downgrade();
13928        cx.spawn_in(window, async move |editor, cx| {
13929            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13930            let Some(project) = project.and_then(|p| p.upgrade()) else {
13931                return;
13932            };
13933            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13934                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13935            }) else {
13936                return;
13937            };
13938
13939            let hide_runnables = project
13940                .update(cx, |project, cx| {
13941                    // Do not display any test indicators in non-dev server remote projects.
13942                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13943                })
13944                .unwrap_or(true);
13945            if hide_runnables {
13946                return;
13947            }
13948            let new_rows =
13949                cx.background_spawn({
13950                    let snapshot = display_snapshot.clone();
13951                    async move {
13952                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13953                    }
13954                })
13955                    .await;
13956            let Ok(lsp_tasks) =
13957                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13958            else {
13959                return;
13960            };
13961            let lsp_tasks = lsp_tasks.await;
13962
13963            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13964                lsp_tasks
13965                    .into_iter()
13966                    .flat_map(|(kind, tasks)| {
13967                        tasks.into_iter().filter_map(move |(location, task)| {
13968                            Some((kind.clone(), location?, task))
13969                        })
13970                    })
13971                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13972                        let buffer = location.target.buffer;
13973                        let buffer_snapshot = buffer.read(cx).snapshot();
13974                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13975                            |(excerpt_id, snapshot, _)| {
13976                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13977                                    display_snapshot
13978                                        .buffer_snapshot
13979                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13980                                } else {
13981                                    None
13982                                }
13983                            },
13984                        );
13985                        if let Some(offset) = offset {
13986                            let task_buffer_range =
13987                                location.target.range.to_point(&buffer_snapshot);
13988                            let context_buffer_range =
13989                                task_buffer_range.to_offset(&buffer_snapshot);
13990                            let context_range = BufferOffset(context_buffer_range.start)
13991                                ..BufferOffset(context_buffer_range.end);
13992
13993                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13994                                .or_insert_with(|| RunnableTasks {
13995                                    templates: Vec::new(),
13996                                    offset,
13997                                    column: task_buffer_range.start.column,
13998                                    extra_variables: HashMap::default(),
13999                                    context_range,
14000                                })
14001                                .templates
14002                                .push((kind, task.original_task().clone()));
14003                        }
14004
14005                        acc
14006                    })
14007            }) else {
14008                return;
14009            };
14010
14011            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14012                buffer.language_settings(cx).tasks.prefer_lsp
14013            }) else {
14014                return;
14015            };
14016
14017            let rows = Self::runnable_rows(
14018                project,
14019                display_snapshot,
14020                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14021                new_rows,
14022                cx.clone(),
14023            );
14024            editor
14025                .update(cx, |editor, _| {
14026                    editor.clear_tasks();
14027                    for (key, mut value) in rows {
14028                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14029                            value.templates.extend(lsp_tasks.templates);
14030                        }
14031
14032                        editor.insert_tasks(key, value);
14033                    }
14034                    for (key, value) in lsp_tasks_by_rows {
14035                        editor.insert_tasks(key, value);
14036                    }
14037                })
14038                .ok();
14039        })
14040    }
14041    fn fetch_runnable_ranges(
14042        snapshot: &DisplaySnapshot,
14043        range: Range<Anchor>,
14044    ) -> Vec<language::RunnableRange> {
14045        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14046    }
14047
14048    fn runnable_rows(
14049        project: Entity<Project>,
14050        snapshot: DisplaySnapshot,
14051        prefer_lsp: bool,
14052        runnable_ranges: Vec<RunnableRange>,
14053        mut cx: AsyncWindowContext,
14054    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
14055        runnable_ranges
14056            .into_iter()
14057            .filter_map(|mut runnable| {
14058                let mut tasks = cx
14059                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14060                    .ok()?;
14061                if prefer_lsp {
14062                    tasks.retain(|(task_kind, _)| {
14063                        !matches!(task_kind, TaskSourceKind::Language { .. })
14064                    });
14065                }
14066                if tasks.is_empty() {
14067                    return None;
14068                }
14069
14070                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14071
14072                let row = snapshot
14073                    .buffer_snapshot
14074                    .buffer_line_for_row(MultiBufferRow(point.row))?
14075                    .1
14076                    .start
14077                    .row;
14078
14079                let context_range =
14080                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14081                Some((
14082                    (runnable.buffer_id, row),
14083                    RunnableTasks {
14084                        templates: tasks,
14085                        offset: snapshot
14086                            .buffer_snapshot
14087                            .anchor_before(runnable.run_range.start),
14088                        context_range,
14089                        column: point.column,
14090                        extra_variables: runnable.extra_captures,
14091                    },
14092                ))
14093            })
14094            .collect()
14095    }
14096
14097    fn templates_with_tags(
14098        project: &Entity<Project>,
14099        runnable: &mut Runnable,
14100        cx: &mut App,
14101    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
14102        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14103            let (worktree_id, file) = project
14104                .buffer_for_id(runnable.buffer, cx)
14105                .and_then(|buffer| buffer.read(cx).file())
14106                .map(|file| (file.worktree_id(cx), file.clone()))
14107                .unzip();
14108
14109            (
14110                project.task_store().read(cx).task_inventory().cloned(),
14111                worktree_id,
14112                file,
14113            )
14114        });
14115
14116        let mut templates_with_tags = mem::take(&mut runnable.tags)
14117            .into_iter()
14118            .flat_map(|RunnableTag(tag)| {
14119                inventory
14120                    .as_ref()
14121                    .into_iter()
14122                    .flat_map(|inventory| {
14123                        inventory.read(cx).list_tasks(
14124                            file.clone(),
14125                            Some(runnable.language.clone()),
14126                            worktree_id,
14127                            cx,
14128                        )
14129                    })
14130                    .filter(move |(_, template)| {
14131                        template.tags.iter().any(|source_tag| source_tag == &tag)
14132                    })
14133            })
14134            .sorted_by_key(|(kind, _)| kind.to_owned())
14135            .collect::<Vec<_>>();
14136        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14137            // Strongest source wins; if we have worktree tag binding, prefer that to
14138            // global and language bindings;
14139            // if we have a global binding, prefer that to language binding.
14140            let first_mismatch = templates_with_tags
14141                .iter()
14142                .position(|(tag_source, _)| tag_source != leading_tag_source);
14143            if let Some(index) = first_mismatch {
14144                templates_with_tags.truncate(index);
14145            }
14146        }
14147
14148        templates_with_tags
14149    }
14150
14151    pub fn move_to_enclosing_bracket(
14152        &mut self,
14153        _: &MoveToEnclosingBracket,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) {
14157        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14158        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14159            s.move_offsets_with(|snapshot, selection| {
14160                let Some(enclosing_bracket_ranges) =
14161                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14162                else {
14163                    return;
14164                };
14165
14166                let mut best_length = usize::MAX;
14167                let mut best_inside = false;
14168                let mut best_in_bracket_range = false;
14169                let mut best_destination = None;
14170                for (open, close) in enclosing_bracket_ranges {
14171                    let close = close.to_inclusive();
14172                    let length = close.end() - open.start;
14173                    let inside = selection.start >= open.end && selection.end <= *close.start();
14174                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14175                        || close.contains(&selection.head());
14176
14177                    // If best is next to a bracket and current isn't, skip
14178                    if !in_bracket_range && best_in_bracket_range {
14179                        continue;
14180                    }
14181
14182                    // Prefer smaller lengths unless best is inside and current isn't
14183                    if length > best_length && (best_inside || !inside) {
14184                        continue;
14185                    }
14186
14187                    best_length = length;
14188                    best_inside = inside;
14189                    best_in_bracket_range = in_bracket_range;
14190                    best_destination = Some(
14191                        if close.contains(&selection.start) && close.contains(&selection.end) {
14192                            if inside { open.end } else { open.start }
14193                        } else if inside {
14194                            *close.start()
14195                        } else {
14196                            *close.end()
14197                        },
14198                    );
14199                }
14200
14201                if let Some(destination) = best_destination {
14202                    selection.collapse_to(destination, SelectionGoal::None);
14203                }
14204            })
14205        });
14206    }
14207
14208    pub fn undo_selection(
14209        &mut self,
14210        _: &UndoSelection,
14211        window: &mut Window,
14212        cx: &mut Context<Self>,
14213    ) {
14214        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14215        self.end_selection(window, cx);
14216        self.selection_history.mode = SelectionHistoryMode::Undoing;
14217        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14218            self.change_selections(None, window, cx, |s| {
14219                s.select_anchors(entry.selections.to_vec())
14220            });
14221            self.select_next_state = entry.select_next_state;
14222            self.select_prev_state = entry.select_prev_state;
14223            self.add_selections_state = entry.add_selections_state;
14224            self.request_autoscroll(Autoscroll::newest(), cx);
14225        }
14226        self.selection_history.mode = SelectionHistoryMode::Normal;
14227    }
14228
14229    pub fn redo_selection(
14230        &mut self,
14231        _: &RedoSelection,
14232        window: &mut Window,
14233        cx: &mut Context<Self>,
14234    ) {
14235        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14236        self.end_selection(window, cx);
14237        self.selection_history.mode = SelectionHistoryMode::Redoing;
14238        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14239            self.change_selections(None, window, cx, |s| {
14240                s.select_anchors(entry.selections.to_vec())
14241            });
14242            self.select_next_state = entry.select_next_state;
14243            self.select_prev_state = entry.select_prev_state;
14244            self.add_selections_state = entry.add_selections_state;
14245            self.request_autoscroll(Autoscroll::newest(), cx);
14246        }
14247        self.selection_history.mode = SelectionHistoryMode::Normal;
14248    }
14249
14250    pub fn expand_excerpts(
14251        &mut self,
14252        action: &ExpandExcerpts,
14253        _: &mut Window,
14254        cx: &mut Context<Self>,
14255    ) {
14256        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14257    }
14258
14259    pub fn expand_excerpts_down(
14260        &mut self,
14261        action: &ExpandExcerptsDown,
14262        _: &mut Window,
14263        cx: &mut Context<Self>,
14264    ) {
14265        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14266    }
14267
14268    pub fn expand_excerpts_up(
14269        &mut self,
14270        action: &ExpandExcerptsUp,
14271        _: &mut Window,
14272        cx: &mut Context<Self>,
14273    ) {
14274        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14275    }
14276
14277    pub fn expand_excerpts_for_direction(
14278        &mut self,
14279        lines: u32,
14280        direction: ExpandExcerptDirection,
14281
14282        cx: &mut Context<Self>,
14283    ) {
14284        let selections = self.selections.disjoint_anchors();
14285
14286        let lines = if lines == 0 {
14287            EditorSettings::get_global(cx).expand_excerpt_lines
14288        } else {
14289            lines
14290        };
14291
14292        self.buffer.update(cx, |buffer, cx| {
14293            let snapshot = buffer.snapshot(cx);
14294            let mut excerpt_ids = selections
14295                .iter()
14296                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14297                .collect::<Vec<_>>();
14298            excerpt_ids.sort();
14299            excerpt_ids.dedup();
14300            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14301        })
14302    }
14303
14304    pub fn expand_excerpt(
14305        &mut self,
14306        excerpt: ExcerptId,
14307        direction: ExpandExcerptDirection,
14308        window: &mut Window,
14309        cx: &mut Context<Self>,
14310    ) {
14311        let current_scroll_position = self.scroll_position(cx);
14312        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14313        let mut should_scroll_up = false;
14314
14315        if direction == ExpandExcerptDirection::Down {
14316            let multi_buffer = self.buffer.read(cx);
14317            let snapshot = multi_buffer.snapshot(cx);
14318            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14319                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14320                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14321                        let buffer_snapshot = buffer.read(cx).snapshot();
14322                        let excerpt_end_row =
14323                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14324                        let last_row = buffer_snapshot.max_point().row;
14325                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14326                        should_scroll_up = lines_below >= lines_to_expand;
14327                    }
14328                }
14329            }
14330        }
14331
14332        self.buffer.update(cx, |buffer, cx| {
14333            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14334        });
14335
14336        if should_scroll_up {
14337            let new_scroll_position =
14338                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14339            self.set_scroll_position(new_scroll_position, window, cx);
14340        }
14341    }
14342
14343    pub fn go_to_singleton_buffer_point(
14344        &mut self,
14345        point: Point,
14346        window: &mut Window,
14347        cx: &mut Context<Self>,
14348    ) {
14349        self.go_to_singleton_buffer_range(point..point, window, cx);
14350    }
14351
14352    pub fn go_to_singleton_buffer_range(
14353        &mut self,
14354        range: Range<Point>,
14355        window: &mut Window,
14356        cx: &mut Context<Self>,
14357    ) {
14358        let multibuffer = self.buffer().read(cx);
14359        let Some(buffer) = multibuffer.as_singleton() else {
14360            return;
14361        };
14362        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14363            return;
14364        };
14365        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14366            return;
14367        };
14368        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14369            s.select_anchor_ranges([start..end])
14370        });
14371    }
14372
14373    pub fn go_to_diagnostic(
14374        &mut self,
14375        _: &GoToDiagnostic,
14376        window: &mut Window,
14377        cx: &mut Context<Self>,
14378    ) {
14379        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14380        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14381    }
14382
14383    pub fn go_to_prev_diagnostic(
14384        &mut self,
14385        _: &GoToPreviousDiagnostic,
14386        window: &mut Window,
14387        cx: &mut Context<Self>,
14388    ) {
14389        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14390        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14391    }
14392
14393    pub fn go_to_diagnostic_impl(
14394        &mut self,
14395        direction: Direction,
14396        window: &mut Window,
14397        cx: &mut Context<Self>,
14398    ) {
14399        let buffer = self.buffer.read(cx).snapshot(cx);
14400        let selection = self.selections.newest::<usize>(cx);
14401
14402        let mut active_group_id = None;
14403        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14404            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14405                active_group_id = Some(active_group.group_id);
14406            }
14407        }
14408
14409        fn filtered(
14410            snapshot: EditorSnapshot,
14411            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14412        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14413            diagnostics
14414                .filter(|entry| entry.range.start != entry.range.end)
14415                .filter(|entry| !entry.diagnostic.is_unnecessary)
14416                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14417        }
14418
14419        let snapshot = self.snapshot(window, cx);
14420        let before = filtered(
14421            snapshot.clone(),
14422            buffer
14423                .diagnostics_in_range(0..selection.start)
14424                .filter(|entry| entry.range.start <= selection.start),
14425        );
14426        let after = filtered(
14427            snapshot,
14428            buffer
14429                .diagnostics_in_range(selection.start..buffer.len())
14430                .filter(|entry| entry.range.start >= selection.start),
14431        );
14432
14433        let mut found: Option<DiagnosticEntry<usize>> = None;
14434        if direction == Direction::Prev {
14435            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14436            {
14437                for diagnostic in prev_diagnostics.into_iter().rev() {
14438                    if diagnostic.range.start != selection.start
14439                        || active_group_id
14440                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14441                    {
14442                        found = Some(diagnostic);
14443                        break 'outer;
14444                    }
14445                }
14446            }
14447        } else {
14448            for diagnostic in after.chain(before) {
14449                if diagnostic.range.start != selection.start
14450                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14451                {
14452                    found = Some(diagnostic);
14453                    break;
14454                }
14455            }
14456        }
14457        let Some(next_diagnostic) = found else {
14458            return;
14459        };
14460
14461        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14462            return;
14463        };
14464        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14465            s.select_ranges(vec![
14466                next_diagnostic.range.start..next_diagnostic.range.start,
14467            ])
14468        });
14469        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14470        self.refresh_inline_completion(false, true, window, cx);
14471    }
14472
14473    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14474        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14475        let snapshot = self.snapshot(window, cx);
14476        let selection = self.selections.newest::<Point>(cx);
14477        self.go_to_hunk_before_or_after_position(
14478            &snapshot,
14479            selection.head(),
14480            Direction::Next,
14481            window,
14482            cx,
14483        );
14484    }
14485
14486    pub fn go_to_hunk_before_or_after_position(
14487        &mut self,
14488        snapshot: &EditorSnapshot,
14489        position: Point,
14490        direction: Direction,
14491        window: &mut Window,
14492        cx: &mut Context<Editor>,
14493    ) {
14494        let row = if direction == Direction::Next {
14495            self.hunk_after_position(snapshot, position)
14496                .map(|hunk| hunk.row_range.start)
14497        } else {
14498            self.hunk_before_position(snapshot, position)
14499        };
14500
14501        if let Some(row) = row {
14502            let destination = Point::new(row.0, 0);
14503            let autoscroll = Autoscroll::center();
14504
14505            self.unfold_ranges(&[destination..destination], false, false, cx);
14506            self.change_selections(Some(autoscroll), window, cx, |s| {
14507                s.select_ranges([destination..destination]);
14508            });
14509        }
14510    }
14511
14512    fn hunk_after_position(
14513        &mut self,
14514        snapshot: &EditorSnapshot,
14515        position: Point,
14516    ) -> Option<MultiBufferDiffHunk> {
14517        snapshot
14518            .buffer_snapshot
14519            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14520            .find(|hunk| hunk.row_range.start.0 > position.row)
14521            .or_else(|| {
14522                snapshot
14523                    .buffer_snapshot
14524                    .diff_hunks_in_range(Point::zero()..position)
14525                    .find(|hunk| hunk.row_range.end.0 < position.row)
14526            })
14527    }
14528
14529    fn go_to_prev_hunk(
14530        &mut self,
14531        _: &GoToPreviousHunk,
14532        window: &mut Window,
14533        cx: &mut Context<Self>,
14534    ) {
14535        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14536        let snapshot = self.snapshot(window, cx);
14537        let selection = self.selections.newest::<Point>(cx);
14538        self.go_to_hunk_before_or_after_position(
14539            &snapshot,
14540            selection.head(),
14541            Direction::Prev,
14542            window,
14543            cx,
14544        );
14545    }
14546
14547    fn hunk_before_position(
14548        &mut self,
14549        snapshot: &EditorSnapshot,
14550        position: Point,
14551    ) -> Option<MultiBufferRow> {
14552        snapshot
14553            .buffer_snapshot
14554            .diff_hunk_before(position)
14555            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14556    }
14557
14558    fn go_to_next_change(
14559        &mut self,
14560        _: &GoToNextChange,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        if let Some(selections) = self
14565            .change_list
14566            .next_change(1, Direction::Next)
14567            .map(|s| s.to_vec())
14568        {
14569            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14570                let map = s.display_map();
14571                s.select_display_ranges(selections.iter().map(|a| {
14572                    let point = a.to_display_point(&map);
14573                    point..point
14574                }))
14575            })
14576        }
14577    }
14578
14579    fn go_to_previous_change(
14580        &mut self,
14581        _: &GoToPreviousChange,
14582        window: &mut Window,
14583        cx: &mut Context<Self>,
14584    ) {
14585        if let Some(selections) = self
14586            .change_list
14587            .next_change(1, Direction::Prev)
14588            .map(|s| s.to_vec())
14589        {
14590            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14591                let map = s.display_map();
14592                s.select_display_ranges(selections.iter().map(|a| {
14593                    let point = a.to_display_point(&map);
14594                    point..point
14595                }))
14596            })
14597        }
14598    }
14599
14600    fn go_to_line<T: 'static>(
14601        &mut self,
14602        position: Anchor,
14603        highlight_color: Option<Hsla>,
14604        window: &mut Window,
14605        cx: &mut Context<Self>,
14606    ) {
14607        let snapshot = self.snapshot(window, cx).display_snapshot;
14608        let position = position.to_point(&snapshot.buffer_snapshot);
14609        let start = snapshot
14610            .buffer_snapshot
14611            .clip_point(Point::new(position.row, 0), Bias::Left);
14612        let end = start + Point::new(1, 0);
14613        let start = snapshot.buffer_snapshot.anchor_before(start);
14614        let end = snapshot.buffer_snapshot.anchor_before(end);
14615
14616        self.highlight_rows::<T>(
14617            start..end,
14618            highlight_color
14619                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14620            Default::default(),
14621            cx,
14622        );
14623
14624        if self.buffer.read(cx).is_singleton() {
14625            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14626        }
14627    }
14628
14629    pub fn go_to_definition(
14630        &mut self,
14631        _: &GoToDefinition,
14632        window: &mut Window,
14633        cx: &mut Context<Self>,
14634    ) -> Task<Result<Navigated>> {
14635        let definition =
14636            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14637        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14638        cx.spawn_in(window, async move |editor, cx| {
14639            if definition.await? == Navigated::Yes {
14640                return Ok(Navigated::Yes);
14641            }
14642            match fallback_strategy {
14643                GoToDefinitionFallback::None => Ok(Navigated::No),
14644                GoToDefinitionFallback::FindAllReferences => {
14645                    match editor.update_in(cx, |editor, window, cx| {
14646                        editor.find_all_references(&FindAllReferences, window, cx)
14647                    })? {
14648                        Some(references) => references.await,
14649                        None => Ok(Navigated::No),
14650                    }
14651                }
14652            }
14653        })
14654    }
14655
14656    pub fn go_to_declaration(
14657        &mut self,
14658        _: &GoToDeclaration,
14659        window: &mut Window,
14660        cx: &mut Context<Self>,
14661    ) -> Task<Result<Navigated>> {
14662        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14663    }
14664
14665    pub fn go_to_declaration_split(
14666        &mut self,
14667        _: &GoToDeclaration,
14668        window: &mut Window,
14669        cx: &mut Context<Self>,
14670    ) -> Task<Result<Navigated>> {
14671        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14672    }
14673
14674    pub fn go_to_implementation(
14675        &mut self,
14676        _: &GoToImplementation,
14677        window: &mut Window,
14678        cx: &mut Context<Self>,
14679    ) -> Task<Result<Navigated>> {
14680        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14681    }
14682
14683    pub fn go_to_implementation_split(
14684        &mut self,
14685        _: &GoToImplementationSplit,
14686        window: &mut Window,
14687        cx: &mut Context<Self>,
14688    ) -> Task<Result<Navigated>> {
14689        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14690    }
14691
14692    pub fn go_to_type_definition(
14693        &mut self,
14694        _: &GoToTypeDefinition,
14695        window: &mut Window,
14696        cx: &mut Context<Self>,
14697    ) -> Task<Result<Navigated>> {
14698        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14699    }
14700
14701    pub fn go_to_definition_split(
14702        &mut self,
14703        _: &GoToDefinitionSplit,
14704        window: &mut Window,
14705        cx: &mut Context<Self>,
14706    ) -> Task<Result<Navigated>> {
14707        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14708    }
14709
14710    pub fn go_to_type_definition_split(
14711        &mut self,
14712        _: &GoToTypeDefinitionSplit,
14713        window: &mut Window,
14714        cx: &mut Context<Self>,
14715    ) -> Task<Result<Navigated>> {
14716        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14717    }
14718
14719    fn go_to_definition_of_kind(
14720        &mut self,
14721        kind: GotoDefinitionKind,
14722        split: bool,
14723        window: &mut Window,
14724        cx: &mut Context<Self>,
14725    ) -> Task<Result<Navigated>> {
14726        let Some(provider) = self.semantics_provider.clone() else {
14727            return Task::ready(Ok(Navigated::No));
14728        };
14729        let head = self.selections.newest::<usize>(cx).head();
14730        let buffer = self.buffer.read(cx);
14731        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14732            text_anchor
14733        } else {
14734            return Task::ready(Ok(Navigated::No));
14735        };
14736
14737        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14738            return Task::ready(Ok(Navigated::No));
14739        };
14740
14741        cx.spawn_in(window, async move |editor, cx| {
14742            let definitions = definitions.await?;
14743            let navigated = editor
14744                .update_in(cx, |editor, window, cx| {
14745                    editor.navigate_to_hover_links(
14746                        Some(kind),
14747                        definitions
14748                            .into_iter()
14749                            .filter(|location| {
14750                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14751                            })
14752                            .map(HoverLink::Text)
14753                            .collect::<Vec<_>>(),
14754                        split,
14755                        window,
14756                        cx,
14757                    )
14758                })?
14759                .await?;
14760            anyhow::Ok(navigated)
14761        })
14762    }
14763
14764    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14765        let selection = self.selections.newest_anchor();
14766        let head = selection.head();
14767        let tail = selection.tail();
14768
14769        let Some((buffer, start_position)) =
14770            self.buffer.read(cx).text_anchor_for_position(head, cx)
14771        else {
14772            return;
14773        };
14774
14775        let end_position = if head != tail {
14776            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14777                return;
14778            };
14779            Some(pos)
14780        } else {
14781            None
14782        };
14783
14784        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14785            let url = if let Some(end_pos) = end_position {
14786                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14787            } else {
14788                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14789            };
14790
14791            if let Some(url) = url {
14792                editor.update(cx, |_, cx| {
14793                    cx.open_url(&url);
14794                })
14795            } else {
14796                Ok(())
14797            }
14798        });
14799
14800        url_finder.detach();
14801    }
14802
14803    pub fn open_selected_filename(
14804        &mut self,
14805        _: &OpenSelectedFilename,
14806        window: &mut Window,
14807        cx: &mut Context<Self>,
14808    ) {
14809        let Some(workspace) = self.workspace() else {
14810            return;
14811        };
14812
14813        let position = self.selections.newest_anchor().head();
14814
14815        let Some((buffer, buffer_position)) =
14816            self.buffer.read(cx).text_anchor_for_position(position, cx)
14817        else {
14818            return;
14819        };
14820
14821        let project = self.project.clone();
14822
14823        cx.spawn_in(window, async move |_, cx| {
14824            let result = find_file(&buffer, project, buffer_position, cx).await;
14825
14826            if let Some((_, path)) = result {
14827                workspace
14828                    .update_in(cx, |workspace, window, cx| {
14829                        workspace.open_resolved_path(path, window, cx)
14830                    })?
14831                    .await?;
14832            }
14833            anyhow::Ok(())
14834        })
14835        .detach();
14836    }
14837
14838    pub(crate) fn navigate_to_hover_links(
14839        &mut self,
14840        kind: Option<GotoDefinitionKind>,
14841        mut definitions: Vec<HoverLink>,
14842        split: bool,
14843        window: &mut Window,
14844        cx: &mut Context<Editor>,
14845    ) -> Task<Result<Navigated>> {
14846        // If there is one definition, just open it directly
14847        if definitions.len() == 1 {
14848            let definition = definitions.pop().unwrap();
14849
14850            enum TargetTaskResult {
14851                Location(Option<Location>),
14852                AlreadyNavigated,
14853            }
14854
14855            let target_task = match definition {
14856                HoverLink::Text(link) => {
14857                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14858                }
14859                HoverLink::InlayHint(lsp_location, server_id) => {
14860                    let computation =
14861                        self.compute_target_location(lsp_location, server_id, window, cx);
14862                    cx.background_spawn(async move {
14863                        let location = computation.await?;
14864                        Ok(TargetTaskResult::Location(location))
14865                    })
14866                }
14867                HoverLink::Url(url) => {
14868                    cx.open_url(&url);
14869                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14870                }
14871                HoverLink::File(path) => {
14872                    if let Some(workspace) = self.workspace() {
14873                        cx.spawn_in(window, async move |_, cx| {
14874                            workspace
14875                                .update_in(cx, |workspace, window, cx| {
14876                                    workspace.open_resolved_path(path, window, cx)
14877                                })?
14878                                .await
14879                                .map(|_| TargetTaskResult::AlreadyNavigated)
14880                        })
14881                    } else {
14882                        Task::ready(Ok(TargetTaskResult::Location(None)))
14883                    }
14884                }
14885            };
14886            cx.spawn_in(window, async move |editor, cx| {
14887                let target = match target_task.await.context("target resolution task")? {
14888                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14889                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14890                    TargetTaskResult::Location(Some(target)) => target,
14891                };
14892
14893                editor.update_in(cx, |editor, window, cx| {
14894                    let Some(workspace) = editor.workspace() else {
14895                        return Navigated::No;
14896                    };
14897                    let pane = workspace.read(cx).active_pane().clone();
14898
14899                    let range = target.range.to_point(target.buffer.read(cx));
14900                    let range = editor.range_for_match(&range);
14901                    let range = collapse_multiline_range(range);
14902
14903                    if !split
14904                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14905                    {
14906                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14907                    } else {
14908                        window.defer(cx, move |window, cx| {
14909                            let target_editor: Entity<Self> =
14910                                workspace.update(cx, |workspace, cx| {
14911                                    let pane = if split {
14912                                        workspace.adjacent_pane(window, cx)
14913                                    } else {
14914                                        workspace.active_pane().clone()
14915                                    };
14916
14917                                    workspace.open_project_item(
14918                                        pane,
14919                                        target.buffer.clone(),
14920                                        true,
14921                                        true,
14922                                        window,
14923                                        cx,
14924                                    )
14925                                });
14926                            target_editor.update(cx, |target_editor, cx| {
14927                                // When selecting a definition in a different buffer, disable the nav history
14928                                // to avoid creating a history entry at the previous cursor location.
14929                                pane.update(cx, |pane, _| pane.disable_history());
14930                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14931                                pane.update(cx, |pane, _| pane.enable_history());
14932                            });
14933                        });
14934                    }
14935                    Navigated::Yes
14936                })
14937            })
14938        } else if !definitions.is_empty() {
14939            cx.spawn_in(window, async move |editor, cx| {
14940                let (title, location_tasks, workspace) = editor
14941                    .update_in(cx, |editor, window, cx| {
14942                        let tab_kind = match kind {
14943                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14944                            _ => "Definitions",
14945                        };
14946                        let title = definitions
14947                            .iter()
14948                            .find_map(|definition| match definition {
14949                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14950                                    let buffer = origin.buffer.read(cx);
14951                                    format!(
14952                                        "{} for {}",
14953                                        tab_kind,
14954                                        buffer
14955                                            .text_for_range(origin.range.clone())
14956                                            .collect::<String>()
14957                                    )
14958                                }),
14959                                HoverLink::InlayHint(_, _) => None,
14960                                HoverLink::Url(_) => None,
14961                                HoverLink::File(_) => None,
14962                            })
14963                            .unwrap_or(tab_kind.to_string());
14964                        let location_tasks = definitions
14965                            .into_iter()
14966                            .map(|definition| match definition {
14967                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14968                                HoverLink::InlayHint(lsp_location, server_id) => editor
14969                                    .compute_target_location(lsp_location, server_id, window, cx),
14970                                HoverLink::Url(_) => Task::ready(Ok(None)),
14971                                HoverLink::File(_) => Task::ready(Ok(None)),
14972                            })
14973                            .collect::<Vec<_>>();
14974                        (title, location_tasks, editor.workspace().clone())
14975                    })
14976                    .context("location tasks preparation")?;
14977
14978                let locations = future::join_all(location_tasks)
14979                    .await
14980                    .into_iter()
14981                    .filter_map(|location| location.transpose())
14982                    .collect::<Result<_>>()
14983                    .context("location tasks")?;
14984
14985                let Some(workspace) = workspace else {
14986                    return Ok(Navigated::No);
14987                };
14988                let opened = workspace
14989                    .update_in(cx, |workspace, window, cx| {
14990                        Self::open_locations_in_multibuffer(
14991                            workspace,
14992                            locations,
14993                            title,
14994                            split,
14995                            MultibufferSelectionMode::First,
14996                            window,
14997                            cx,
14998                        )
14999                    })
15000                    .ok();
15001
15002                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15003            })
15004        } else {
15005            Task::ready(Ok(Navigated::No))
15006        }
15007    }
15008
15009    fn compute_target_location(
15010        &self,
15011        lsp_location: lsp::Location,
15012        server_id: LanguageServerId,
15013        window: &mut Window,
15014        cx: &mut Context<Self>,
15015    ) -> Task<anyhow::Result<Option<Location>>> {
15016        let Some(project) = self.project.clone() else {
15017            return Task::ready(Ok(None));
15018        };
15019
15020        cx.spawn_in(window, async move |editor, cx| {
15021            let location_task = editor.update(cx, |_, cx| {
15022                project.update(cx, |project, cx| {
15023                    let language_server_name = project
15024                        .language_server_statuses(cx)
15025                        .find(|(id, _)| server_id == *id)
15026                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15027                    language_server_name.map(|language_server_name| {
15028                        project.open_local_buffer_via_lsp(
15029                            lsp_location.uri.clone(),
15030                            server_id,
15031                            language_server_name,
15032                            cx,
15033                        )
15034                    })
15035                })
15036            })?;
15037            let location = match location_task {
15038                Some(task) => Some({
15039                    let target_buffer_handle = task.await.context("open local buffer")?;
15040                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15041                        let target_start = target_buffer
15042                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15043                        let target_end = target_buffer
15044                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15045                        target_buffer.anchor_after(target_start)
15046                            ..target_buffer.anchor_before(target_end)
15047                    })?;
15048                    Location {
15049                        buffer: target_buffer_handle,
15050                        range,
15051                    }
15052                }),
15053                None => None,
15054            };
15055            Ok(location)
15056        })
15057    }
15058
15059    pub fn find_all_references(
15060        &mut self,
15061        _: &FindAllReferences,
15062        window: &mut Window,
15063        cx: &mut Context<Self>,
15064    ) -> Option<Task<Result<Navigated>>> {
15065        let selection = self.selections.newest::<usize>(cx);
15066        let multi_buffer = self.buffer.read(cx);
15067        let head = selection.head();
15068
15069        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15070        let head_anchor = multi_buffer_snapshot.anchor_at(
15071            head,
15072            if head < selection.tail() {
15073                Bias::Right
15074            } else {
15075                Bias::Left
15076            },
15077        );
15078
15079        match self
15080            .find_all_references_task_sources
15081            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15082        {
15083            Ok(_) => {
15084                log::info!(
15085                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15086                );
15087                return None;
15088            }
15089            Err(i) => {
15090                self.find_all_references_task_sources.insert(i, head_anchor);
15091            }
15092        }
15093
15094        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15095        let workspace = self.workspace()?;
15096        let project = workspace.read(cx).project().clone();
15097        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15098        Some(cx.spawn_in(window, async move |editor, cx| {
15099            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15100                if let Ok(i) = editor
15101                    .find_all_references_task_sources
15102                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15103                {
15104                    editor.find_all_references_task_sources.remove(i);
15105                }
15106            });
15107
15108            let locations = references.await?;
15109            if locations.is_empty() {
15110                return anyhow::Ok(Navigated::No);
15111            }
15112
15113            workspace.update_in(cx, |workspace, window, cx| {
15114                let title = locations
15115                    .first()
15116                    .as_ref()
15117                    .map(|location| {
15118                        let buffer = location.buffer.read(cx);
15119                        format!(
15120                            "References to `{}`",
15121                            buffer
15122                                .text_for_range(location.range.clone())
15123                                .collect::<String>()
15124                        )
15125                    })
15126                    .unwrap();
15127                Self::open_locations_in_multibuffer(
15128                    workspace,
15129                    locations,
15130                    title,
15131                    false,
15132                    MultibufferSelectionMode::First,
15133                    window,
15134                    cx,
15135                );
15136                Navigated::Yes
15137            })
15138        }))
15139    }
15140
15141    /// Opens a multibuffer with the given project locations in it
15142    pub fn open_locations_in_multibuffer(
15143        workspace: &mut Workspace,
15144        mut locations: Vec<Location>,
15145        title: String,
15146        split: bool,
15147        multibuffer_selection_mode: MultibufferSelectionMode,
15148        window: &mut Window,
15149        cx: &mut Context<Workspace>,
15150    ) {
15151        // If there are multiple definitions, open them in a multibuffer
15152        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15153        let mut locations = locations.into_iter().peekable();
15154        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15155        let capability = workspace.project().read(cx).capability();
15156
15157        let excerpt_buffer = cx.new(|cx| {
15158            let mut multibuffer = MultiBuffer::new(capability);
15159            while let Some(location) = locations.next() {
15160                let buffer = location.buffer.read(cx);
15161                let mut ranges_for_buffer = Vec::new();
15162                let range = location.range.to_point(buffer);
15163                ranges_for_buffer.push(range.clone());
15164
15165                while let Some(next_location) = locations.peek() {
15166                    if next_location.buffer == location.buffer {
15167                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15168                        locations.next();
15169                    } else {
15170                        break;
15171                    }
15172                }
15173
15174                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15175                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15176                    PathKey::for_buffer(&location.buffer, cx),
15177                    location.buffer.clone(),
15178                    ranges_for_buffer,
15179                    DEFAULT_MULTIBUFFER_CONTEXT,
15180                    cx,
15181                );
15182                ranges.extend(new_ranges)
15183            }
15184
15185            multibuffer.with_title(title)
15186        });
15187
15188        let editor = cx.new(|cx| {
15189            Editor::for_multibuffer(
15190                excerpt_buffer,
15191                Some(workspace.project().clone()),
15192                window,
15193                cx,
15194            )
15195        });
15196        editor.update(cx, |editor, cx| {
15197            match multibuffer_selection_mode {
15198                MultibufferSelectionMode::First => {
15199                    if let Some(first_range) = ranges.first() {
15200                        editor.change_selections(None, window, cx, |selections| {
15201                            selections.clear_disjoint();
15202                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15203                        });
15204                    }
15205                    editor.highlight_background::<Self>(
15206                        &ranges,
15207                        |theme| theme.editor_highlighted_line_background,
15208                        cx,
15209                    );
15210                }
15211                MultibufferSelectionMode::All => {
15212                    editor.change_selections(None, window, cx, |selections| {
15213                        selections.clear_disjoint();
15214                        selections.select_anchor_ranges(ranges);
15215                    });
15216                }
15217            }
15218            editor.register_buffers_with_language_servers(cx);
15219        });
15220
15221        let item = Box::new(editor);
15222        let item_id = item.item_id();
15223
15224        if split {
15225            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15226        } else {
15227            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15228                let (preview_item_id, preview_item_idx) =
15229                    workspace.active_pane().read_with(cx, |pane, _| {
15230                        (pane.preview_item_id(), pane.preview_item_idx())
15231                    });
15232
15233                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15234
15235                if let Some(preview_item_id) = preview_item_id {
15236                    workspace.active_pane().update(cx, |pane, cx| {
15237                        pane.remove_item(preview_item_id, false, false, window, cx);
15238                    });
15239                }
15240            } else {
15241                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15242            }
15243        }
15244        workspace.active_pane().update(cx, |pane, cx| {
15245            pane.set_preview_item_id(Some(item_id), cx);
15246        });
15247    }
15248
15249    pub fn rename(
15250        &mut self,
15251        _: &Rename,
15252        window: &mut Window,
15253        cx: &mut Context<Self>,
15254    ) -> Option<Task<Result<()>>> {
15255        use language::ToOffset as _;
15256
15257        let provider = self.semantics_provider.clone()?;
15258        let selection = self.selections.newest_anchor().clone();
15259        let (cursor_buffer, cursor_buffer_position) = self
15260            .buffer
15261            .read(cx)
15262            .text_anchor_for_position(selection.head(), cx)?;
15263        let (tail_buffer, cursor_buffer_position_end) = self
15264            .buffer
15265            .read(cx)
15266            .text_anchor_for_position(selection.tail(), cx)?;
15267        if tail_buffer != cursor_buffer {
15268            return None;
15269        }
15270
15271        let snapshot = cursor_buffer.read(cx).snapshot();
15272        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15273        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15274        let prepare_rename = provider
15275            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15276            .unwrap_or_else(|| Task::ready(Ok(None)));
15277        drop(snapshot);
15278
15279        Some(cx.spawn_in(window, async move |this, cx| {
15280            let rename_range = if let Some(range) = prepare_rename.await? {
15281                Some(range)
15282            } else {
15283                this.update(cx, |this, cx| {
15284                    let buffer = this.buffer.read(cx).snapshot(cx);
15285                    let mut buffer_highlights = this
15286                        .document_highlights_for_position(selection.head(), &buffer)
15287                        .filter(|highlight| {
15288                            highlight.start.excerpt_id == selection.head().excerpt_id
15289                                && highlight.end.excerpt_id == selection.head().excerpt_id
15290                        });
15291                    buffer_highlights
15292                        .next()
15293                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15294                })?
15295            };
15296            if let Some(rename_range) = rename_range {
15297                this.update_in(cx, |this, window, cx| {
15298                    let snapshot = cursor_buffer.read(cx).snapshot();
15299                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15300                    let cursor_offset_in_rename_range =
15301                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15302                    let cursor_offset_in_rename_range_end =
15303                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15304
15305                    this.take_rename(false, window, cx);
15306                    let buffer = this.buffer.read(cx).read(cx);
15307                    let cursor_offset = selection.head().to_offset(&buffer);
15308                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15309                    let rename_end = rename_start + rename_buffer_range.len();
15310                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15311                    let mut old_highlight_id = None;
15312                    let old_name: Arc<str> = buffer
15313                        .chunks(rename_start..rename_end, true)
15314                        .map(|chunk| {
15315                            if old_highlight_id.is_none() {
15316                                old_highlight_id = chunk.syntax_highlight_id;
15317                            }
15318                            chunk.text
15319                        })
15320                        .collect::<String>()
15321                        .into();
15322
15323                    drop(buffer);
15324
15325                    // Position the selection in the rename editor so that it matches the current selection.
15326                    this.show_local_selections = false;
15327                    let rename_editor = cx.new(|cx| {
15328                        let mut editor = Editor::single_line(window, cx);
15329                        editor.buffer.update(cx, |buffer, cx| {
15330                            buffer.edit([(0..0, old_name.clone())], None, cx)
15331                        });
15332                        let rename_selection_range = match cursor_offset_in_rename_range
15333                            .cmp(&cursor_offset_in_rename_range_end)
15334                        {
15335                            Ordering::Equal => {
15336                                editor.select_all(&SelectAll, window, cx);
15337                                return editor;
15338                            }
15339                            Ordering::Less => {
15340                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15341                            }
15342                            Ordering::Greater => {
15343                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15344                            }
15345                        };
15346                        if rename_selection_range.end > old_name.len() {
15347                            editor.select_all(&SelectAll, window, cx);
15348                        } else {
15349                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15350                                s.select_ranges([rename_selection_range]);
15351                            });
15352                        }
15353                        editor
15354                    });
15355                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15356                        if e == &EditorEvent::Focused {
15357                            cx.emit(EditorEvent::FocusedIn)
15358                        }
15359                    })
15360                    .detach();
15361
15362                    let write_highlights =
15363                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15364                    let read_highlights =
15365                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15366                    let ranges = write_highlights
15367                        .iter()
15368                        .flat_map(|(_, ranges)| ranges.iter())
15369                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15370                        .cloned()
15371                        .collect();
15372
15373                    this.highlight_text::<Rename>(
15374                        ranges,
15375                        HighlightStyle {
15376                            fade_out: Some(0.6),
15377                            ..Default::default()
15378                        },
15379                        cx,
15380                    );
15381                    let rename_focus_handle = rename_editor.focus_handle(cx);
15382                    window.focus(&rename_focus_handle);
15383                    let block_id = this.insert_blocks(
15384                        [BlockProperties {
15385                            style: BlockStyle::Flex,
15386                            placement: BlockPlacement::Below(range.start),
15387                            height: Some(1),
15388                            render: Arc::new({
15389                                let rename_editor = rename_editor.clone();
15390                                move |cx: &mut BlockContext| {
15391                                    let mut text_style = cx.editor_style.text.clone();
15392                                    if let Some(highlight_style) = old_highlight_id
15393                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15394                                    {
15395                                        text_style = text_style.highlight(highlight_style);
15396                                    }
15397                                    div()
15398                                        .block_mouse_except_scroll()
15399                                        .pl(cx.anchor_x)
15400                                        .child(EditorElement::new(
15401                                            &rename_editor,
15402                                            EditorStyle {
15403                                                background: cx.theme().system().transparent,
15404                                                local_player: cx.editor_style.local_player,
15405                                                text: text_style,
15406                                                scrollbar_width: cx.editor_style.scrollbar_width,
15407                                                syntax: cx.editor_style.syntax.clone(),
15408                                                status: cx.editor_style.status.clone(),
15409                                                inlay_hints_style: HighlightStyle {
15410                                                    font_weight: Some(FontWeight::BOLD),
15411                                                    ..make_inlay_hints_style(cx.app)
15412                                                },
15413                                                inline_completion_styles: make_suggestion_styles(
15414                                                    cx.app,
15415                                                ),
15416                                                ..EditorStyle::default()
15417                                            },
15418                                        ))
15419                                        .into_any_element()
15420                                }
15421                            }),
15422                            priority: 0,
15423                            render_in_minimap: true,
15424                        }],
15425                        Some(Autoscroll::fit()),
15426                        cx,
15427                    )[0];
15428                    this.pending_rename = Some(RenameState {
15429                        range,
15430                        old_name,
15431                        editor: rename_editor,
15432                        block_id,
15433                    });
15434                })?;
15435            }
15436
15437            Ok(())
15438        }))
15439    }
15440
15441    pub fn confirm_rename(
15442        &mut self,
15443        _: &ConfirmRename,
15444        window: &mut Window,
15445        cx: &mut Context<Self>,
15446    ) -> Option<Task<Result<()>>> {
15447        let rename = self.take_rename(false, window, cx)?;
15448        let workspace = self.workspace()?.downgrade();
15449        let (buffer, start) = self
15450            .buffer
15451            .read(cx)
15452            .text_anchor_for_position(rename.range.start, cx)?;
15453        let (end_buffer, _) = self
15454            .buffer
15455            .read(cx)
15456            .text_anchor_for_position(rename.range.end, cx)?;
15457        if buffer != end_buffer {
15458            return None;
15459        }
15460
15461        let old_name = rename.old_name;
15462        let new_name = rename.editor.read(cx).text(cx);
15463
15464        let rename = self.semantics_provider.as_ref()?.perform_rename(
15465            &buffer,
15466            start,
15467            new_name.clone(),
15468            cx,
15469        )?;
15470
15471        Some(cx.spawn_in(window, async move |editor, cx| {
15472            let project_transaction = rename.await?;
15473            Self::open_project_transaction(
15474                &editor,
15475                workspace,
15476                project_transaction,
15477                format!("Rename: {}{}", old_name, new_name),
15478                cx,
15479            )
15480            .await?;
15481
15482            editor.update(cx, |editor, cx| {
15483                editor.refresh_document_highlights(cx);
15484            })?;
15485            Ok(())
15486        }))
15487    }
15488
15489    fn take_rename(
15490        &mut self,
15491        moving_cursor: bool,
15492        window: &mut Window,
15493        cx: &mut Context<Self>,
15494    ) -> Option<RenameState> {
15495        let rename = self.pending_rename.take()?;
15496        if rename.editor.focus_handle(cx).is_focused(window) {
15497            window.focus(&self.focus_handle);
15498        }
15499
15500        self.remove_blocks(
15501            [rename.block_id].into_iter().collect(),
15502            Some(Autoscroll::fit()),
15503            cx,
15504        );
15505        self.clear_highlights::<Rename>(cx);
15506        self.show_local_selections = true;
15507
15508        if moving_cursor {
15509            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15510                editor.selections.newest::<usize>(cx).head()
15511            });
15512
15513            // Update the selection to match the position of the selection inside
15514            // the rename editor.
15515            let snapshot = self.buffer.read(cx).read(cx);
15516            let rename_range = rename.range.to_offset(&snapshot);
15517            let cursor_in_editor = snapshot
15518                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15519                .min(rename_range.end);
15520            drop(snapshot);
15521
15522            self.change_selections(None, window, cx, |s| {
15523                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15524            });
15525        } else {
15526            self.refresh_document_highlights(cx);
15527        }
15528
15529        Some(rename)
15530    }
15531
15532    pub fn pending_rename(&self) -> Option<&RenameState> {
15533        self.pending_rename.as_ref()
15534    }
15535
15536    fn format(
15537        &mut self,
15538        _: &Format,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) -> Option<Task<Result<()>>> {
15542        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15543
15544        let project = match &self.project {
15545            Some(project) => project.clone(),
15546            None => return None,
15547        };
15548
15549        Some(self.perform_format(
15550            project,
15551            FormatTrigger::Manual,
15552            FormatTarget::Buffers,
15553            window,
15554            cx,
15555        ))
15556    }
15557
15558    fn format_selections(
15559        &mut self,
15560        _: &FormatSelections,
15561        window: &mut Window,
15562        cx: &mut Context<Self>,
15563    ) -> Option<Task<Result<()>>> {
15564        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15565
15566        let project = match &self.project {
15567            Some(project) => project.clone(),
15568            None => return None,
15569        };
15570
15571        let ranges = self
15572            .selections
15573            .all_adjusted(cx)
15574            .into_iter()
15575            .map(|selection| selection.range())
15576            .collect_vec();
15577
15578        Some(self.perform_format(
15579            project,
15580            FormatTrigger::Manual,
15581            FormatTarget::Ranges(ranges),
15582            window,
15583            cx,
15584        ))
15585    }
15586
15587    fn perform_format(
15588        &mut self,
15589        project: Entity<Project>,
15590        trigger: FormatTrigger,
15591        target: FormatTarget,
15592        window: &mut Window,
15593        cx: &mut Context<Self>,
15594    ) -> Task<Result<()>> {
15595        let buffer = self.buffer.clone();
15596        let (buffers, target) = match target {
15597            FormatTarget::Buffers => {
15598                let mut buffers = buffer.read(cx).all_buffers();
15599                if trigger == FormatTrigger::Save {
15600                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15601                }
15602                (buffers, LspFormatTarget::Buffers)
15603            }
15604            FormatTarget::Ranges(selection_ranges) => {
15605                let multi_buffer = buffer.read(cx);
15606                let snapshot = multi_buffer.read(cx);
15607                let mut buffers = HashSet::default();
15608                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15609                    BTreeMap::new();
15610                for selection_range in selection_ranges {
15611                    for (buffer, buffer_range, _) in
15612                        snapshot.range_to_buffer_ranges(selection_range)
15613                    {
15614                        let buffer_id = buffer.remote_id();
15615                        let start = buffer.anchor_before(buffer_range.start);
15616                        let end = buffer.anchor_after(buffer_range.end);
15617                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15618                        buffer_id_to_ranges
15619                            .entry(buffer_id)
15620                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15621                            .or_insert_with(|| vec![start..end]);
15622                    }
15623                }
15624                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15625            }
15626        };
15627
15628        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15629        let selections_prev = transaction_id_prev
15630            .and_then(|transaction_id_prev| {
15631                // default to selections as they were after the last edit, if we have them,
15632                // instead of how they are now.
15633                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15634                // will take you back to where you made the last edit, instead of staying where you scrolled
15635                self.selection_history
15636                    .transaction(transaction_id_prev)
15637                    .map(|t| t.0.clone())
15638            })
15639            .unwrap_or_else(|| {
15640                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15641                self.selections.disjoint_anchors()
15642            });
15643
15644        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15645        let format = project.update(cx, |project, cx| {
15646            project.format(buffers, target, true, trigger, cx)
15647        });
15648
15649        cx.spawn_in(window, async move |editor, cx| {
15650            let transaction = futures::select_biased! {
15651                transaction = format.log_err().fuse() => transaction,
15652                () = timeout => {
15653                    log::warn!("timed out waiting for formatting");
15654                    None
15655                }
15656            };
15657
15658            buffer
15659                .update(cx, |buffer, cx| {
15660                    if let Some(transaction) = transaction {
15661                        if !buffer.is_singleton() {
15662                            buffer.push_transaction(&transaction.0, cx);
15663                        }
15664                    }
15665                    cx.notify();
15666                })
15667                .ok();
15668
15669            if let Some(transaction_id_now) =
15670                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15671            {
15672                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15673                if has_new_transaction {
15674                    _ = editor.update(cx, |editor, _| {
15675                        editor
15676                            .selection_history
15677                            .insert_transaction(transaction_id_now, selections_prev);
15678                    });
15679                }
15680            }
15681
15682            Ok(())
15683        })
15684    }
15685
15686    fn organize_imports(
15687        &mut self,
15688        _: &OrganizeImports,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Option<Task<Result<()>>> {
15692        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15693        let project = match &self.project {
15694            Some(project) => project.clone(),
15695            None => return None,
15696        };
15697        Some(self.perform_code_action_kind(
15698            project,
15699            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15700            window,
15701            cx,
15702        ))
15703    }
15704
15705    fn perform_code_action_kind(
15706        &mut self,
15707        project: Entity<Project>,
15708        kind: CodeActionKind,
15709        window: &mut Window,
15710        cx: &mut Context<Self>,
15711    ) -> Task<Result<()>> {
15712        let buffer = self.buffer.clone();
15713        let buffers = buffer.read(cx).all_buffers();
15714        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15715        let apply_action = project.update(cx, |project, cx| {
15716            project.apply_code_action_kind(buffers, kind, true, cx)
15717        });
15718        cx.spawn_in(window, async move |_, cx| {
15719            let transaction = futures::select_biased! {
15720                () = timeout => {
15721                    log::warn!("timed out waiting for executing code action");
15722                    None
15723                }
15724                transaction = apply_action.log_err().fuse() => transaction,
15725            };
15726            buffer
15727                .update(cx, |buffer, cx| {
15728                    // check if we need this
15729                    if let Some(transaction) = transaction {
15730                        if !buffer.is_singleton() {
15731                            buffer.push_transaction(&transaction.0, cx);
15732                        }
15733                    }
15734                    cx.notify();
15735                })
15736                .ok();
15737            Ok(())
15738        })
15739    }
15740
15741    fn restart_language_server(
15742        &mut self,
15743        _: &RestartLanguageServer,
15744        _: &mut Window,
15745        cx: &mut Context<Self>,
15746    ) {
15747        if let Some(project) = self.project.clone() {
15748            self.buffer.update(cx, |multi_buffer, cx| {
15749                project.update(cx, |project, cx| {
15750                    project.restart_language_servers_for_buffers(
15751                        multi_buffer.all_buffers().into_iter().collect(),
15752                        cx,
15753                    );
15754                });
15755            })
15756        }
15757    }
15758
15759    fn stop_language_server(
15760        &mut self,
15761        _: &StopLanguageServer,
15762        _: &mut Window,
15763        cx: &mut Context<Self>,
15764    ) {
15765        if let Some(project) = self.project.clone() {
15766            self.buffer.update(cx, |multi_buffer, cx| {
15767                project.update(cx, |project, cx| {
15768                    project.stop_language_servers_for_buffers(
15769                        multi_buffer.all_buffers().into_iter().collect(),
15770                        cx,
15771                    );
15772                    cx.emit(project::Event::RefreshInlayHints);
15773                });
15774            });
15775        }
15776    }
15777
15778    fn cancel_language_server_work(
15779        workspace: &mut Workspace,
15780        _: &actions::CancelLanguageServerWork,
15781        _: &mut Window,
15782        cx: &mut Context<Workspace>,
15783    ) {
15784        let project = workspace.project();
15785        let buffers = workspace
15786            .active_item(cx)
15787            .and_then(|item| item.act_as::<Editor>(cx))
15788            .map_or(HashSet::default(), |editor| {
15789                editor.read(cx).buffer.read(cx).all_buffers()
15790            });
15791        project.update(cx, |project, cx| {
15792            project.cancel_language_server_work_for_buffers(buffers, cx);
15793        });
15794    }
15795
15796    fn show_character_palette(
15797        &mut self,
15798        _: &ShowCharacterPalette,
15799        window: &mut Window,
15800        _: &mut Context<Self>,
15801    ) {
15802        window.show_character_palette();
15803    }
15804
15805    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15806        if self.mode.is_minimap() {
15807            return;
15808        }
15809
15810        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15811            let buffer = self.buffer.read(cx).snapshot(cx);
15812            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15813            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15814            let is_valid = buffer
15815                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15816                .any(|entry| {
15817                    entry.diagnostic.is_primary
15818                        && !entry.range.is_empty()
15819                        && entry.range.start == primary_range_start
15820                        && entry.diagnostic.message == active_diagnostics.active_message
15821                });
15822
15823            if !is_valid {
15824                self.dismiss_diagnostics(cx);
15825            }
15826        }
15827    }
15828
15829    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15830        match &self.active_diagnostics {
15831            ActiveDiagnostic::Group(group) => Some(group),
15832            _ => None,
15833        }
15834    }
15835
15836    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15837        self.dismiss_diagnostics(cx);
15838        self.active_diagnostics = ActiveDiagnostic::All;
15839    }
15840
15841    fn activate_diagnostics(
15842        &mut self,
15843        buffer_id: BufferId,
15844        diagnostic: DiagnosticEntry<usize>,
15845        window: &mut Window,
15846        cx: &mut Context<Self>,
15847    ) {
15848        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15849            return;
15850        }
15851        self.dismiss_diagnostics(cx);
15852        let snapshot = self.snapshot(window, cx);
15853        let buffer = self.buffer.read(cx).snapshot(cx);
15854        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15855            return;
15856        };
15857
15858        let diagnostic_group = buffer
15859            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15860            .collect::<Vec<_>>();
15861
15862        let blocks =
15863            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15864
15865        let blocks = self.display_map.update(cx, |display_map, cx| {
15866            display_map.insert_blocks(blocks, cx).into_iter().collect()
15867        });
15868        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15869            active_range: buffer.anchor_before(diagnostic.range.start)
15870                ..buffer.anchor_after(diagnostic.range.end),
15871            active_message: diagnostic.diagnostic.message.clone(),
15872            group_id: diagnostic.diagnostic.group_id,
15873            blocks,
15874        });
15875        cx.notify();
15876    }
15877
15878    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15879        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15880            return;
15881        };
15882
15883        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15884        if let ActiveDiagnostic::Group(group) = prev {
15885            self.display_map.update(cx, |display_map, cx| {
15886                display_map.remove_blocks(group.blocks, cx);
15887            });
15888            cx.notify();
15889        }
15890    }
15891
15892    /// Disable inline diagnostics rendering for this editor.
15893    pub fn disable_inline_diagnostics(&mut self) {
15894        self.inline_diagnostics_enabled = false;
15895        self.inline_diagnostics_update = Task::ready(());
15896        self.inline_diagnostics.clear();
15897    }
15898
15899    pub fn diagnostics_enabled(&self) -> bool {
15900        self.mode.is_full()
15901    }
15902
15903    pub fn inline_diagnostics_enabled(&self) -> bool {
15904        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15905    }
15906
15907    pub fn show_inline_diagnostics(&self) -> bool {
15908        self.show_inline_diagnostics
15909    }
15910
15911    pub fn toggle_inline_diagnostics(
15912        &mut self,
15913        _: &ToggleInlineDiagnostics,
15914        window: &mut Window,
15915        cx: &mut Context<Editor>,
15916    ) {
15917        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15918        self.refresh_inline_diagnostics(false, window, cx);
15919    }
15920
15921    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15922        self.diagnostics_max_severity = severity;
15923        self.display_map.update(cx, |display_map, _| {
15924            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15925        });
15926    }
15927
15928    pub fn toggle_diagnostics(
15929        &mut self,
15930        _: &ToggleDiagnostics,
15931        window: &mut Window,
15932        cx: &mut Context<Editor>,
15933    ) {
15934        if !self.diagnostics_enabled() {
15935            return;
15936        }
15937
15938        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15939            EditorSettings::get_global(cx)
15940                .diagnostics_max_severity
15941                .filter(|severity| severity != &DiagnosticSeverity::Off)
15942                .unwrap_or(DiagnosticSeverity::Hint)
15943        } else {
15944            DiagnosticSeverity::Off
15945        };
15946        self.set_max_diagnostics_severity(new_severity, cx);
15947        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15948            self.active_diagnostics = ActiveDiagnostic::None;
15949            self.inline_diagnostics_update = Task::ready(());
15950            self.inline_diagnostics.clear();
15951        } else {
15952            self.refresh_inline_diagnostics(false, window, cx);
15953        }
15954
15955        cx.notify();
15956    }
15957
15958    pub fn toggle_minimap(
15959        &mut self,
15960        _: &ToggleMinimap,
15961        window: &mut Window,
15962        cx: &mut Context<Editor>,
15963    ) {
15964        if self.supports_minimap(cx) {
15965            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15966        }
15967    }
15968
15969    fn refresh_inline_diagnostics(
15970        &mut self,
15971        debounce: bool,
15972        window: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) {
15975        let max_severity = ProjectSettings::get_global(cx)
15976            .diagnostics
15977            .inline
15978            .max_severity
15979            .unwrap_or(self.diagnostics_max_severity);
15980
15981        if !self.inline_diagnostics_enabled()
15982            || !self.show_inline_diagnostics
15983            || max_severity == DiagnosticSeverity::Off
15984        {
15985            self.inline_diagnostics_update = Task::ready(());
15986            self.inline_diagnostics.clear();
15987            return;
15988        }
15989
15990        let debounce_ms = ProjectSettings::get_global(cx)
15991            .diagnostics
15992            .inline
15993            .update_debounce_ms;
15994        let debounce = if debounce && debounce_ms > 0 {
15995            Some(Duration::from_millis(debounce_ms))
15996        } else {
15997            None
15998        };
15999        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16000            if let Some(debounce) = debounce {
16001                cx.background_executor().timer(debounce).await;
16002            }
16003            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16004                editor
16005                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16006                    .ok()
16007            }) else {
16008                return;
16009            };
16010
16011            let new_inline_diagnostics = cx
16012                .background_spawn(async move {
16013                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16014                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16015                        let message = diagnostic_entry
16016                            .diagnostic
16017                            .message
16018                            .split_once('\n')
16019                            .map(|(line, _)| line)
16020                            .map(SharedString::new)
16021                            .unwrap_or_else(|| {
16022                                SharedString::from(diagnostic_entry.diagnostic.message)
16023                            });
16024                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16025                        let (Ok(i) | Err(i)) = inline_diagnostics
16026                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16027                        inline_diagnostics.insert(
16028                            i,
16029                            (
16030                                start_anchor,
16031                                InlineDiagnostic {
16032                                    message,
16033                                    group_id: diagnostic_entry.diagnostic.group_id,
16034                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16035                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16036                                    severity: diagnostic_entry.diagnostic.severity,
16037                                },
16038                            ),
16039                        );
16040                    }
16041                    inline_diagnostics
16042                })
16043                .await;
16044
16045            editor
16046                .update(cx, |editor, cx| {
16047                    editor.inline_diagnostics = new_inline_diagnostics;
16048                    cx.notify();
16049                })
16050                .ok();
16051        });
16052    }
16053
16054    fn pull_diagnostics(
16055        &mut self,
16056        buffer_id: Option<BufferId>,
16057        window: &Window,
16058        cx: &mut Context<Self>,
16059    ) -> Option<()> {
16060        let project = self.project.as_ref()?.downgrade();
16061        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16062            .diagnostics
16063            .lsp_pull_diagnostics;
16064        if !pull_diagnostics_settings.enabled {
16065            return None;
16066        }
16067        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16068        let mut buffers = self.buffer.read(cx).all_buffers();
16069        if let Some(buffer_id) = buffer_id {
16070            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16071        }
16072
16073        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16074            cx.background_executor().timer(debounce).await;
16075
16076            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16077                buffers
16078                    .into_iter()
16079                    .flat_map(|buffer| {
16080                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16081                    })
16082                    .collect::<FuturesUnordered<_>>()
16083            }) else {
16084                return;
16085            };
16086
16087            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16088                match pull_task {
16089                    Ok(()) => {
16090                        if editor
16091                            .update_in(cx, |editor, window, cx| {
16092                                editor.update_diagnostics_state(window, cx);
16093                            })
16094                            .is_err()
16095                        {
16096                            return;
16097                        }
16098                    }
16099                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16100                }
16101            }
16102        });
16103
16104        Some(())
16105    }
16106
16107    pub fn set_selections_from_remote(
16108        &mut self,
16109        selections: Vec<Selection<Anchor>>,
16110        pending_selection: Option<Selection<Anchor>>,
16111        window: &mut Window,
16112        cx: &mut Context<Self>,
16113    ) {
16114        let old_cursor_position = self.selections.newest_anchor().head();
16115        self.selections.change_with(cx, |s| {
16116            s.select_anchors(selections);
16117            if let Some(pending_selection) = pending_selection {
16118                s.set_pending(pending_selection, SelectMode::Character);
16119            } else {
16120                s.clear_pending();
16121            }
16122        });
16123        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16124    }
16125
16126    pub fn transact(
16127        &mut self,
16128        window: &mut Window,
16129        cx: &mut Context<Self>,
16130        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16131    ) -> Option<TransactionId> {
16132        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16133            this.start_transaction_at(Instant::now(), window, cx);
16134            update(this, window, cx);
16135            this.end_transaction_at(Instant::now(), cx)
16136        })
16137    }
16138
16139    pub fn start_transaction_at(
16140        &mut self,
16141        now: Instant,
16142        window: &mut Window,
16143        cx: &mut Context<Self>,
16144    ) {
16145        self.end_selection(window, cx);
16146        if let Some(tx_id) = self
16147            .buffer
16148            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16149        {
16150            self.selection_history
16151                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16152            cx.emit(EditorEvent::TransactionBegun {
16153                transaction_id: tx_id,
16154            })
16155        }
16156    }
16157
16158    pub fn end_transaction_at(
16159        &mut self,
16160        now: Instant,
16161        cx: &mut Context<Self>,
16162    ) -> Option<TransactionId> {
16163        if let Some(transaction_id) = self
16164            .buffer
16165            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16166        {
16167            if let Some((_, end_selections)) =
16168                self.selection_history.transaction_mut(transaction_id)
16169            {
16170                *end_selections = Some(self.selections.disjoint_anchors());
16171            } else {
16172                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16173            }
16174
16175            cx.emit(EditorEvent::Edited { transaction_id });
16176            Some(transaction_id)
16177        } else {
16178            None
16179        }
16180    }
16181
16182    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16183        if self.selection_mark_mode {
16184            self.change_selections(None, window, cx, |s| {
16185                s.move_with(|_, sel| {
16186                    sel.collapse_to(sel.head(), SelectionGoal::None);
16187                });
16188            })
16189        }
16190        self.selection_mark_mode = true;
16191        cx.notify();
16192    }
16193
16194    pub fn swap_selection_ends(
16195        &mut self,
16196        _: &actions::SwapSelectionEnds,
16197        window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        self.change_selections(None, window, cx, |s| {
16201            s.move_with(|_, sel| {
16202                if sel.start != sel.end {
16203                    sel.reversed = !sel.reversed
16204                }
16205            });
16206        });
16207        self.request_autoscroll(Autoscroll::newest(), cx);
16208        cx.notify();
16209    }
16210
16211    pub fn toggle_fold(
16212        &mut self,
16213        _: &actions::ToggleFold,
16214        window: &mut Window,
16215        cx: &mut Context<Self>,
16216    ) {
16217        if self.is_singleton(cx) {
16218            let selection = self.selections.newest::<Point>(cx);
16219
16220            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16221            let range = if selection.is_empty() {
16222                let point = selection.head().to_display_point(&display_map);
16223                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16224                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16225                    .to_point(&display_map);
16226                start..end
16227            } else {
16228                selection.range()
16229            };
16230            if display_map.folds_in_range(range).next().is_some() {
16231                self.unfold_lines(&Default::default(), window, cx)
16232            } else {
16233                self.fold(&Default::default(), window, cx)
16234            }
16235        } else {
16236            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16237            let buffer_ids: HashSet<_> = self
16238                .selections
16239                .disjoint_anchor_ranges()
16240                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16241                .collect();
16242
16243            let should_unfold = buffer_ids
16244                .iter()
16245                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16246
16247            for buffer_id in buffer_ids {
16248                if should_unfold {
16249                    self.unfold_buffer(buffer_id, cx);
16250                } else {
16251                    self.fold_buffer(buffer_id, cx);
16252                }
16253            }
16254        }
16255    }
16256
16257    pub fn toggle_fold_recursive(
16258        &mut self,
16259        _: &actions::ToggleFoldRecursive,
16260        window: &mut Window,
16261        cx: &mut Context<Self>,
16262    ) {
16263        let selection = self.selections.newest::<Point>(cx);
16264
16265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16266        let range = if selection.is_empty() {
16267            let point = selection.head().to_display_point(&display_map);
16268            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16269            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16270                .to_point(&display_map);
16271            start..end
16272        } else {
16273            selection.range()
16274        };
16275        if display_map.folds_in_range(range).next().is_some() {
16276            self.unfold_recursive(&Default::default(), window, cx)
16277        } else {
16278            self.fold_recursive(&Default::default(), window, cx)
16279        }
16280    }
16281
16282    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16283        if self.is_singleton(cx) {
16284            let mut to_fold = Vec::new();
16285            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16286            let selections = self.selections.all_adjusted(cx);
16287
16288            for selection in selections {
16289                let range = selection.range().sorted();
16290                let buffer_start_row = range.start.row;
16291
16292                if range.start.row != range.end.row {
16293                    let mut found = false;
16294                    let mut row = range.start.row;
16295                    while row <= range.end.row {
16296                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16297                        {
16298                            found = true;
16299                            row = crease.range().end.row + 1;
16300                            to_fold.push(crease);
16301                        } else {
16302                            row += 1
16303                        }
16304                    }
16305                    if found {
16306                        continue;
16307                    }
16308                }
16309
16310                for row in (0..=range.start.row).rev() {
16311                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16312                        if crease.range().end.row >= buffer_start_row {
16313                            to_fold.push(crease);
16314                            if row <= range.start.row {
16315                                break;
16316                            }
16317                        }
16318                    }
16319                }
16320            }
16321
16322            self.fold_creases(to_fold, true, window, cx);
16323        } else {
16324            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16325            let buffer_ids = self
16326                .selections
16327                .disjoint_anchor_ranges()
16328                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16329                .collect::<HashSet<_>>();
16330            for buffer_id in buffer_ids {
16331                self.fold_buffer(buffer_id, cx);
16332            }
16333        }
16334    }
16335
16336    fn fold_at_level(
16337        &mut self,
16338        fold_at: &FoldAtLevel,
16339        window: &mut Window,
16340        cx: &mut Context<Self>,
16341    ) {
16342        if !self.buffer.read(cx).is_singleton() {
16343            return;
16344        }
16345
16346        let fold_at_level = fold_at.0;
16347        let snapshot = self.buffer.read(cx).snapshot(cx);
16348        let mut to_fold = Vec::new();
16349        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16350
16351        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16352            while start_row < end_row {
16353                match self
16354                    .snapshot(window, cx)
16355                    .crease_for_buffer_row(MultiBufferRow(start_row))
16356                {
16357                    Some(crease) => {
16358                        let nested_start_row = crease.range().start.row + 1;
16359                        let nested_end_row = crease.range().end.row;
16360
16361                        if current_level < fold_at_level {
16362                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16363                        } else if current_level == fold_at_level {
16364                            to_fold.push(crease);
16365                        }
16366
16367                        start_row = nested_end_row + 1;
16368                    }
16369                    None => start_row += 1,
16370                }
16371            }
16372        }
16373
16374        self.fold_creases(to_fold, true, window, cx);
16375    }
16376
16377    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16378        if self.buffer.read(cx).is_singleton() {
16379            let mut fold_ranges = Vec::new();
16380            let snapshot = self.buffer.read(cx).snapshot(cx);
16381
16382            for row in 0..snapshot.max_row().0 {
16383                if let Some(foldable_range) = self
16384                    .snapshot(window, cx)
16385                    .crease_for_buffer_row(MultiBufferRow(row))
16386                {
16387                    fold_ranges.push(foldable_range);
16388                }
16389            }
16390
16391            self.fold_creases(fold_ranges, true, window, cx);
16392        } else {
16393            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16394                editor
16395                    .update_in(cx, |editor, _, cx| {
16396                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16397                            editor.fold_buffer(buffer_id, cx);
16398                        }
16399                    })
16400                    .ok();
16401            });
16402        }
16403    }
16404
16405    pub fn fold_function_bodies(
16406        &mut self,
16407        _: &actions::FoldFunctionBodies,
16408        window: &mut Window,
16409        cx: &mut Context<Self>,
16410    ) {
16411        let snapshot = self.buffer.read(cx).snapshot(cx);
16412
16413        let ranges = snapshot
16414            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16415            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16416            .collect::<Vec<_>>();
16417
16418        let creases = ranges
16419            .into_iter()
16420            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16421            .collect();
16422
16423        self.fold_creases(creases, true, window, cx);
16424    }
16425
16426    pub fn fold_recursive(
16427        &mut self,
16428        _: &actions::FoldRecursive,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) {
16432        let mut to_fold = Vec::new();
16433        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16434        let selections = self.selections.all_adjusted(cx);
16435
16436        for selection in selections {
16437            let range = selection.range().sorted();
16438            let buffer_start_row = range.start.row;
16439
16440            if range.start.row != range.end.row {
16441                let mut found = false;
16442                for row in range.start.row..=range.end.row {
16443                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16444                        found = true;
16445                        to_fold.push(crease);
16446                    }
16447                }
16448                if found {
16449                    continue;
16450                }
16451            }
16452
16453            for row in (0..=range.start.row).rev() {
16454                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16455                    if crease.range().end.row >= buffer_start_row {
16456                        to_fold.push(crease);
16457                    } else {
16458                        break;
16459                    }
16460                }
16461            }
16462        }
16463
16464        self.fold_creases(to_fold, true, window, cx);
16465    }
16466
16467    pub fn fold_at(
16468        &mut self,
16469        buffer_row: MultiBufferRow,
16470        window: &mut Window,
16471        cx: &mut Context<Self>,
16472    ) {
16473        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16474
16475        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16476            let autoscroll = self
16477                .selections
16478                .all::<Point>(cx)
16479                .iter()
16480                .any(|selection| crease.range().overlaps(&selection.range()));
16481
16482            self.fold_creases(vec![crease], autoscroll, window, cx);
16483        }
16484    }
16485
16486    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16487        if self.is_singleton(cx) {
16488            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16489            let buffer = &display_map.buffer_snapshot;
16490            let selections = self.selections.all::<Point>(cx);
16491            let ranges = selections
16492                .iter()
16493                .map(|s| {
16494                    let range = s.display_range(&display_map).sorted();
16495                    let mut start = range.start.to_point(&display_map);
16496                    let mut end = range.end.to_point(&display_map);
16497                    start.column = 0;
16498                    end.column = buffer.line_len(MultiBufferRow(end.row));
16499                    start..end
16500                })
16501                .collect::<Vec<_>>();
16502
16503            self.unfold_ranges(&ranges, true, true, cx);
16504        } else {
16505            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16506            let buffer_ids = self
16507                .selections
16508                .disjoint_anchor_ranges()
16509                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16510                .collect::<HashSet<_>>();
16511            for buffer_id in buffer_ids {
16512                self.unfold_buffer(buffer_id, cx);
16513            }
16514        }
16515    }
16516
16517    pub fn unfold_recursive(
16518        &mut self,
16519        _: &UnfoldRecursive,
16520        _window: &mut Window,
16521        cx: &mut Context<Self>,
16522    ) {
16523        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16524        let selections = self.selections.all::<Point>(cx);
16525        let ranges = selections
16526            .iter()
16527            .map(|s| {
16528                let mut range = s.display_range(&display_map).sorted();
16529                *range.start.column_mut() = 0;
16530                *range.end.column_mut() = display_map.line_len(range.end.row());
16531                let start = range.start.to_point(&display_map);
16532                let end = range.end.to_point(&display_map);
16533                start..end
16534            })
16535            .collect::<Vec<_>>();
16536
16537        self.unfold_ranges(&ranges, true, true, cx);
16538    }
16539
16540    pub fn unfold_at(
16541        &mut self,
16542        buffer_row: MultiBufferRow,
16543        _window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) {
16546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16547
16548        let intersection_range = Point::new(buffer_row.0, 0)
16549            ..Point::new(
16550                buffer_row.0,
16551                display_map.buffer_snapshot.line_len(buffer_row),
16552            );
16553
16554        let autoscroll = self
16555            .selections
16556            .all::<Point>(cx)
16557            .iter()
16558            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16559
16560        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16561    }
16562
16563    pub fn unfold_all(
16564        &mut self,
16565        _: &actions::UnfoldAll,
16566        _window: &mut Window,
16567        cx: &mut Context<Self>,
16568    ) {
16569        if self.buffer.read(cx).is_singleton() {
16570            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16571            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16572        } else {
16573            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16574                editor
16575                    .update(cx, |editor, cx| {
16576                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16577                            editor.unfold_buffer(buffer_id, cx);
16578                        }
16579                    })
16580                    .ok();
16581            });
16582        }
16583    }
16584
16585    pub fn fold_selected_ranges(
16586        &mut self,
16587        _: &FoldSelectedRanges,
16588        window: &mut Window,
16589        cx: &mut Context<Self>,
16590    ) {
16591        let selections = self.selections.all_adjusted(cx);
16592        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16593        let ranges = selections
16594            .into_iter()
16595            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16596            .collect::<Vec<_>>();
16597        self.fold_creases(ranges, true, window, cx);
16598    }
16599
16600    pub fn fold_ranges<T: ToOffset + Clone>(
16601        &mut self,
16602        ranges: Vec<Range<T>>,
16603        auto_scroll: bool,
16604        window: &mut Window,
16605        cx: &mut Context<Self>,
16606    ) {
16607        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16608        let ranges = ranges
16609            .into_iter()
16610            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16611            .collect::<Vec<_>>();
16612        self.fold_creases(ranges, auto_scroll, window, cx);
16613    }
16614
16615    pub fn fold_creases<T: ToOffset + Clone>(
16616        &mut self,
16617        creases: Vec<Crease<T>>,
16618        auto_scroll: bool,
16619        _window: &mut Window,
16620        cx: &mut Context<Self>,
16621    ) {
16622        if creases.is_empty() {
16623            return;
16624        }
16625
16626        let mut buffers_affected = HashSet::default();
16627        let multi_buffer = self.buffer().read(cx);
16628        for crease in &creases {
16629            if let Some((_, buffer, _)) =
16630                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16631            {
16632                buffers_affected.insert(buffer.read(cx).remote_id());
16633            };
16634        }
16635
16636        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16637
16638        if auto_scroll {
16639            self.request_autoscroll(Autoscroll::fit(), cx);
16640        }
16641
16642        cx.notify();
16643
16644        self.scrollbar_marker_state.dirty = true;
16645        self.folds_did_change(cx);
16646    }
16647
16648    /// Removes any folds whose ranges intersect any of the given ranges.
16649    pub fn unfold_ranges<T: ToOffset + Clone>(
16650        &mut self,
16651        ranges: &[Range<T>],
16652        inclusive: bool,
16653        auto_scroll: bool,
16654        cx: &mut Context<Self>,
16655    ) {
16656        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16657            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16658        });
16659        self.folds_did_change(cx);
16660    }
16661
16662    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16663        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16664            return;
16665        }
16666        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16667        self.display_map.update(cx, |display_map, cx| {
16668            display_map.fold_buffers([buffer_id], cx)
16669        });
16670        cx.emit(EditorEvent::BufferFoldToggled {
16671            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16672            folded: true,
16673        });
16674        cx.notify();
16675    }
16676
16677    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16678        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16679            return;
16680        }
16681        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16682        self.display_map.update(cx, |display_map, cx| {
16683            display_map.unfold_buffers([buffer_id], cx);
16684        });
16685        cx.emit(EditorEvent::BufferFoldToggled {
16686            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16687            folded: false,
16688        });
16689        cx.notify();
16690    }
16691
16692    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16693        self.display_map.read(cx).is_buffer_folded(buffer)
16694    }
16695
16696    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16697        self.display_map.read(cx).folded_buffers()
16698    }
16699
16700    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16701        self.display_map.update(cx, |display_map, cx| {
16702            display_map.disable_header_for_buffer(buffer_id, cx);
16703        });
16704        cx.notify();
16705    }
16706
16707    /// Removes any folds with the given ranges.
16708    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16709        &mut self,
16710        ranges: &[Range<T>],
16711        type_id: TypeId,
16712        auto_scroll: bool,
16713        cx: &mut Context<Self>,
16714    ) {
16715        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16716            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16717        });
16718        self.folds_did_change(cx);
16719    }
16720
16721    fn remove_folds_with<T: ToOffset + Clone>(
16722        &mut self,
16723        ranges: &[Range<T>],
16724        auto_scroll: bool,
16725        cx: &mut Context<Self>,
16726        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16727    ) {
16728        if ranges.is_empty() {
16729            return;
16730        }
16731
16732        let mut buffers_affected = HashSet::default();
16733        let multi_buffer = self.buffer().read(cx);
16734        for range in ranges {
16735            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16736                buffers_affected.insert(buffer.read(cx).remote_id());
16737            };
16738        }
16739
16740        self.display_map.update(cx, update);
16741
16742        if auto_scroll {
16743            self.request_autoscroll(Autoscroll::fit(), cx);
16744        }
16745
16746        cx.notify();
16747        self.scrollbar_marker_state.dirty = true;
16748        self.active_indent_guides_state.dirty = true;
16749    }
16750
16751    pub fn update_fold_widths(
16752        &mut self,
16753        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16754        cx: &mut Context<Self>,
16755    ) -> bool {
16756        self.display_map
16757            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16758    }
16759
16760    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16761        self.display_map.read(cx).fold_placeholder.clone()
16762    }
16763
16764    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16765        self.buffer.update(cx, |buffer, cx| {
16766            buffer.set_all_diff_hunks_expanded(cx);
16767        });
16768    }
16769
16770    pub fn expand_all_diff_hunks(
16771        &mut self,
16772        _: &ExpandAllDiffHunks,
16773        _window: &mut Window,
16774        cx: &mut Context<Self>,
16775    ) {
16776        self.buffer.update(cx, |buffer, cx| {
16777            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16778        });
16779    }
16780
16781    pub fn toggle_selected_diff_hunks(
16782        &mut self,
16783        _: &ToggleSelectedDiffHunks,
16784        _window: &mut Window,
16785        cx: &mut Context<Self>,
16786    ) {
16787        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16788        self.toggle_diff_hunks_in_ranges(ranges, cx);
16789    }
16790
16791    pub fn diff_hunks_in_ranges<'a>(
16792        &'a self,
16793        ranges: &'a [Range<Anchor>],
16794        buffer: &'a MultiBufferSnapshot,
16795    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16796        ranges.iter().flat_map(move |range| {
16797            let end_excerpt_id = range.end.excerpt_id;
16798            let range = range.to_point(buffer);
16799            let mut peek_end = range.end;
16800            if range.end.row < buffer.max_row().0 {
16801                peek_end = Point::new(range.end.row + 1, 0);
16802            }
16803            buffer
16804                .diff_hunks_in_range(range.start..peek_end)
16805                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16806        })
16807    }
16808
16809    pub fn has_stageable_diff_hunks_in_ranges(
16810        &self,
16811        ranges: &[Range<Anchor>],
16812        snapshot: &MultiBufferSnapshot,
16813    ) -> bool {
16814        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16815        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16816    }
16817
16818    pub fn toggle_staged_selected_diff_hunks(
16819        &mut self,
16820        _: &::git::ToggleStaged,
16821        _: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) {
16824        let snapshot = self.buffer.read(cx).snapshot(cx);
16825        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16826        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16827        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16828    }
16829
16830    pub fn set_render_diff_hunk_controls(
16831        &mut self,
16832        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16833        cx: &mut Context<Self>,
16834    ) {
16835        self.render_diff_hunk_controls = render_diff_hunk_controls;
16836        cx.notify();
16837    }
16838
16839    pub fn stage_and_next(
16840        &mut self,
16841        _: &::git::StageAndNext,
16842        window: &mut Window,
16843        cx: &mut Context<Self>,
16844    ) {
16845        self.do_stage_or_unstage_and_next(true, window, cx);
16846    }
16847
16848    pub fn unstage_and_next(
16849        &mut self,
16850        _: &::git::UnstageAndNext,
16851        window: &mut Window,
16852        cx: &mut Context<Self>,
16853    ) {
16854        self.do_stage_or_unstage_and_next(false, window, cx);
16855    }
16856
16857    pub fn stage_or_unstage_diff_hunks(
16858        &mut self,
16859        stage: bool,
16860        ranges: Vec<Range<Anchor>>,
16861        cx: &mut Context<Self>,
16862    ) {
16863        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16864        cx.spawn(async move |this, cx| {
16865            task.await?;
16866            this.update(cx, |this, cx| {
16867                let snapshot = this.buffer.read(cx).snapshot(cx);
16868                let chunk_by = this
16869                    .diff_hunks_in_ranges(&ranges, &snapshot)
16870                    .chunk_by(|hunk| hunk.buffer_id);
16871                for (buffer_id, hunks) in &chunk_by {
16872                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16873                }
16874            })
16875        })
16876        .detach_and_log_err(cx);
16877    }
16878
16879    fn save_buffers_for_ranges_if_needed(
16880        &mut self,
16881        ranges: &[Range<Anchor>],
16882        cx: &mut Context<Editor>,
16883    ) -> Task<Result<()>> {
16884        let multibuffer = self.buffer.read(cx);
16885        let snapshot = multibuffer.read(cx);
16886        let buffer_ids: HashSet<_> = ranges
16887            .iter()
16888            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16889            .collect();
16890        drop(snapshot);
16891
16892        let mut buffers = HashSet::default();
16893        for buffer_id in buffer_ids {
16894            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16895                let buffer = buffer_entity.read(cx);
16896                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16897                {
16898                    buffers.insert(buffer_entity);
16899                }
16900            }
16901        }
16902
16903        if let Some(project) = &self.project {
16904            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16905        } else {
16906            Task::ready(Ok(()))
16907        }
16908    }
16909
16910    fn do_stage_or_unstage_and_next(
16911        &mut self,
16912        stage: bool,
16913        window: &mut Window,
16914        cx: &mut Context<Self>,
16915    ) {
16916        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16917
16918        if ranges.iter().any(|range| range.start != range.end) {
16919            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16920            return;
16921        }
16922
16923        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16924        let snapshot = self.snapshot(window, cx);
16925        let position = self.selections.newest::<Point>(cx).head();
16926        let mut row = snapshot
16927            .buffer_snapshot
16928            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16929            .find(|hunk| hunk.row_range.start.0 > position.row)
16930            .map(|hunk| hunk.row_range.start);
16931
16932        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16933        // Outside of the project diff editor, wrap around to the beginning.
16934        if !all_diff_hunks_expanded {
16935            row = row.or_else(|| {
16936                snapshot
16937                    .buffer_snapshot
16938                    .diff_hunks_in_range(Point::zero()..position)
16939                    .find(|hunk| hunk.row_range.end.0 < position.row)
16940                    .map(|hunk| hunk.row_range.start)
16941            });
16942        }
16943
16944        if let Some(row) = row {
16945            let destination = Point::new(row.0, 0);
16946            let autoscroll = Autoscroll::center();
16947
16948            self.unfold_ranges(&[destination..destination], false, false, cx);
16949            self.change_selections(Some(autoscroll), window, cx, |s| {
16950                s.select_ranges([destination..destination]);
16951            });
16952        }
16953    }
16954
16955    fn do_stage_or_unstage(
16956        &self,
16957        stage: bool,
16958        buffer_id: BufferId,
16959        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16960        cx: &mut App,
16961    ) -> Option<()> {
16962        let project = self.project.as_ref()?;
16963        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16964        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16965        let buffer_snapshot = buffer.read(cx).snapshot();
16966        let file_exists = buffer_snapshot
16967            .file()
16968            .is_some_and(|file| file.disk_state().exists());
16969        diff.update(cx, |diff, cx| {
16970            diff.stage_or_unstage_hunks(
16971                stage,
16972                &hunks
16973                    .map(|hunk| buffer_diff::DiffHunk {
16974                        buffer_range: hunk.buffer_range,
16975                        diff_base_byte_range: hunk.diff_base_byte_range,
16976                        secondary_status: hunk.secondary_status,
16977                        range: Point::zero()..Point::zero(), // unused
16978                    })
16979                    .collect::<Vec<_>>(),
16980                &buffer_snapshot,
16981                file_exists,
16982                cx,
16983            )
16984        });
16985        None
16986    }
16987
16988    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16989        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16990        self.buffer
16991            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16992    }
16993
16994    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16995        self.buffer.update(cx, |buffer, cx| {
16996            let ranges = vec![Anchor::min()..Anchor::max()];
16997            if !buffer.all_diff_hunks_expanded()
16998                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16999            {
17000                buffer.collapse_diff_hunks(ranges, cx);
17001                true
17002            } else {
17003                false
17004            }
17005        })
17006    }
17007
17008    fn toggle_diff_hunks_in_ranges(
17009        &mut self,
17010        ranges: Vec<Range<Anchor>>,
17011        cx: &mut Context<Editor>,
17012    ) {
17013        self.buffer.update(cx, |buffer, cx| {
17014            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17015            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17016        })
17017    }
17018
17019    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17020        self.buffer.update(cx, |buffer, cx| {
17021            let snapshot = buffer.snapshot(cx);
17022            let excerpt_id = range.end.excerpt_id;
17023            let point_range = range.to_point(&snapshot);
17024            let expand = !buffer.single_hunk_is_expanded(range, cx);
17025            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17026        })
17027    }
17028
17029    pub(crate) fn apply_all_diff_hunks(
17030        &mut self,
17031        _: &ApplyAllDiffHunks,
17032        window: &mut Window,
17033        cx: &mut Context<Self>,
17034    ) {
17035        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17036
17037        let buffers = self.buffer.read(cx).all_buffers();
17038        for branch_buffer in buffers {
17039            branch_buffer.update(cx, |branch_buffer, cx| {
17040                branch_buffer.merge_into_base(Vec::new(), cx);
17041            });
17042        }
17043
17044        if let Some(project) = self.project.clone() {
17045            self.save(true, project, window, cx).detach_and_log_err(cx);
17046        }
17047    }
17048
17049    pub(crate) fn apply_selected_diff_hunks(
17050        &mut self,
17051        _: &ApplyDiffHunk,
17052        window: &mut Window,
17053        cx: &mut Context<Self>,
17054    ) {
17055        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17056        let snapshot = self.snapshot(window, cx);
17057        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17058        let mut ranges_by_buffer = HashMap::default();
17059        self.transact(window, cx, |editor, _window, cx| {
17060            for hunk in hunks {
17061                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17062                    ranges_by_buffer
17063                        .entry(buffer.clone())
17064                        .or_insert_with(Vec::new)
17065                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17066                }
17067            }
17068
17069            for (buffer, ranges) in ranges_by_buffer {
17070                buffer.update(cx, |buffer, cx| {
17071                    buffer.merge_into_base(ranges, cx);
17072                });
17073            }
17074        });
17075
17076        if let Some(project) = self.project.clone() {
17077            self.save(true, project, window, cx).detach_and_log_err(cx);
17078        }
17079    }
17080
17081    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17082        if hovered != self.gutter_hovered {
17083            self.gutter_hovered = hovered;
17084            cx.notify();
17085        }
17086    }
17087
17088    pub fn insert_blocks(
17089        &mut self,
17090        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17091        autoscroll: Option<Autoscroll>,
17092        cx: &mut Context<Self>,
17093    ) -> Vec<CustomBlockId> {
17094        let blocks = self
17095            .display_map
17096            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17097        if let Some(autoscroll) = autoscroll {
17098            self.request_autoscroll(autoscroll, cx);
17099        }
17100        cx.notify();
17101        blocks
17102    }
17103
17104    pub fn resize_blocks(
17105        &mut self,
17106        heights: HashMap<CustomBlockId, u32>,
17107        autoscroll: Option<Autoscroll>,
17108        cx: &mut Context<Self>,
17109    ) {
17110        self.display_map
17111            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17112        if let Some(autoscroll) = autoscroll {
17113            self.request_autoscroll(autoscroll, cx);
17114        }
17115        cx.notify();
17116    }
17117
17118    pub fn replace_blocks(
17119        &mut self,
17120        renderers: HashMap<CustomBlockId, RenderBlock>,
17121        autoscroll: Option<Autoscroll>,
17122        cx: &mut Context<Self>,
17123    ) {
17124        self.display_map
17125            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17126        if let Some(autoscroll) = autoscroll {
17127            self.request_autoscroll(autoscroll, cx);
17128        }
17129        cx.notify();
17130    }
17131
17132    pub fn remove_blocks(
17133        &mut self,
17134        block_ids: HashSet<CustomBlockId>,
17135        autoscroll: Option<Autoscroll>,
17136        cx: &mut Context<Self>,
17137    ) {
17138        self.display_map.update(cx, |display_map, cx| {
17139            display_map.remove_blocks(block_ids, cx)
17140        });
17141        if let Some(autoscroll) = autoscroll {
17142            self.request_autoscroll(autoscroll, cx);
17143        }
17144        cx.notify();
17145    }
17146
17147    pub fn row_for_block(
17148        &self,
17149        block_id: CustomBlockId,
17150        cx: &mut Context<Self>,
17151    ) -> Option<DisplayRow> {
17152        self.display_map
17153            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17154    }
17155
17156    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17157        self.focused_block = Some(focused_block);
17158    }
17159
17160    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17161        self.focused_block.take()
17162    }
17163
17164    pub fn insert_creases(
17165        &mut self,
17166        creases: impl IntoIterator<Item = Crease<Anchor>>,
17167        cx: &mut Context<Self>,
17168    ) -> Vec<CreaseId> {
17169        self.display_map
17170            .update(cx, |map, cx| map.insert_creases(creases, cx))
17171    }
17172
17173    pub fn remove_creases(
17174        &mut self,
17175        ids: impl IntoIterator<Item = CreaseId>,
17176        cx: &mut Context<Self>,
17177    ) -> Vec<(CreaseId, Range<Anchor>)> {
17178        self.display_map
17179            .update(cx, |map, cx| map.remove_creases(ids, cx))
17180    }
17181
17182    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17183        self.display_map
17184            .update(cx, |map, cx| map.snapshot(cx))
17185            .longest_row()
17186    }
17187
17188    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17189        self.display_map
17190            .update(cx, |map, cx| map.snapshot(cx))
17191            .max_point()
17192    }
17193
17194    pub fn text(&self, cx: &App) -> String {
17195        self.buffer.read(cx).read(cx).text()
17196    }
17197
17198    pub fn is_empty(&self, cx: &App) -> bool {
17199        self.buffer.read(cx).read(cx).is_empty()
17200    }
17201
17202    pub fn text_option(&self, cx: &App) -> Option<String> {
17203        let text = self.text(cx);
17204        let text = text.trim();
17205
17206        if text.is_empty() {
17207            return None;
17208        }
17209
17210        Some(text.to_string())
17211    }
17212
17213    pub fn set_text(
17214        &mut self,
17215        text: impl Into<Arc<str>>,
17216        window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) {
17219        self.transact(window, cx, |this, _, cx| {
17220            this.buffer
17221                .read(cx)
17222                .as_singleton()
17223                .expect("you can only call set_text on editors for singleton buffers")
17224                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17225        });
17226    }
17227
17228    pub fn display_text(&self, cx: &mut App) -> String {
17229        self.display_map
17230            .update(cx, |map, cx| map.snapshot(cx))
17231            .text()
17232    }
17233
17234    fn create_minimap(
17235        &self,
17236        minimap_settings: MinimapSettings,
17237        window: &mut Window,
17238        cx: &mut Context<Self>,
17239    ) -> Option<Entity<Self>> {
17240        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17241            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17242    }
17243
17244    fn initialize_new_minimap(
17245        &self,
17246        minimap_settings: MinimapSettings,
17247        window: &mut Window,
17248        cx: &mut Context<Self>,
17249    ) -> Entity<Self> {
17250        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17251
17252        let mut minimap = Editor::new_internal(
17253            EditorMode::Minimap {
17254                parent: cx.weak_entity(),
17255            },
17256            self.buffer.clone(),
17257            self.project.clone(),
17258            Some(self.display_map.clone()),
17259            window,
17260            cx,
17261        );
17262        minimap.scroll_manager.clone_state(&self.scroll_manager);
17263        minimap.set_text_style_refinement(TextStyleRefinement {
17264            font_size: Some(MINIMAP_FONT_SIZE),
17265            font_weight: Some(MINIMAP_FONT_WEIGHT),
17266            ..Default::default()
17267        });
17268        minimap.update_minimap_configuration(minimap_settings, cx);
17269        cx.new(|_| minimap)
17270    }
17271
17272    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17273        let current_line_highlight = minimap_settings
17274            .current_line_highlight
17275            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17276        self.set_current_line_highlight(Some(current_line_highlight));
17277    }
17278
17279    pub fn minimap(&self) -> Option<&Entity<Self>> {
17280        self.minimap
17281            .as_ref()
17282            .filter(|_| self.minimap_visibility.visible())
17283    }
17284
17285    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17286        let mut wrap_guides = smallvec![];
17287
17288        if self.show_wrap_guides == Some(false) {
17289            return wrap_guides;
17290        }
17291
17292        let settings = self.buffer.read(cx).language_settings(cx);
17293        if settings.show_wrap_guides {
17294            match self.soft_wrap_mode(cx) {
17295                SoftWrap::Column(soft_wrap) => {
17296                    wrap_guides.push((soft_wrap as usize, true));
17297                }
17298                SoftWrap::Bounded(soft_wrap) => {
17299                    wrap_guides.push((soft_wrap as usize, true));
17300                }
17301                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17302            }
17303            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17304        }
17305
17306        wrap_guides
17307    }
17308
17309    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17310        let settings = self.buffer.read(cx).language_settings(cx);
17311        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17312        match mode {
17313            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17314                SoftWrap::None
17315            }
17316            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17317            language_settings::SoftWrap::PreferredLineLength => {
17318                SoftWrap::Column(settings.preferred_line_length)
17319            }
17320            language_settings::SoftWrap::Bounded => {
17321                SoftWrap::Bounded(settings.preferred_line_length)
17322            }
17323        }
17324    }
17325
17326    pub fn set_soft_wrap_mode(
17327        &mut self,
17328        mode: language_settings::SoftWrap,
17329
17330        cx: &mut Context<Self>,
17331    ) {
17332        self.soft_wrap_mode_override = Some(mode);
17333        cx.notify();
17334    }
17335
17336    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17337        self.hard_wrap = hard_wrap;
17338        cx.notify();
17339    }
17340
17341    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17342        self.text_style_refinement = Some(style);
17343    }
17344
17345    /// called by the Element so we know what style we were most recently rendered with.
17346    pub(crate) fn set_style(
17347        &mut self,
17348        style: EditorStyle,
17349        window: &mut Window,
17350        cx: &mut Context<Self>,
17351    ) {
17352        // We intentionally do not inform the display map about the minimap style
17353        // so that wrapping is not recalculated and stays consistent for the editor
17354        // and its linked minimap.
17355        if !self.mode.is_minimap() {
17356            let rem_size = window.rem_size();
17357            self.display_map.update(cx, |map, cx| {
17358                map.set_font(
17359                    style.text.font(),
17360                    style.text.font_size.to_pixels(rem_size),
17361                    cx,
17362                )
17363            });
17364        }
17365        self.style = Some(style);
17366    }
17367
17368    pub fn style(&self) -> Option<&EditorStyle> {
17369        self.style.as_ref()
17370    }
17371
17372    // Called by the element. This method is not designed to be called outside of the editor
17373    // element's layout code because it does not notify when rewrapping is computed synchronously.
17374    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17375        self.display_map
17376            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17377    }
17378
17379    pub fn set_soft_wrap(&mut self) {
17380        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17381    }
17382
17383    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17384        if self.soft_wrap_mode_override.is_some() {
17385            self.soft_wrap_mode_override.take();
17386        } else {
17387            let soft_wrap = match self.soft_wrap_mode(cx) {
17388                SoftWrap::GitDiff => return,
17389                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17390                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17391                    language_settings::SoftWrap::None
17392                }
17393            };
17394            self.soft_wrap_mode_override = Some(soft_wrap);
17395        }
17396        cx.notify();
17397    }
17398
17399    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17400        let Some(workspace) = self.workspace() else {
17401            return;
17402        };
17403        let fs = workspace.read(cx).app_state().fs.clone();
17404        let current_show = TabBarSettings::get_global(cx).show;
17405        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17406            setting.show = Some(!current_show);
17407        });
17408    }
17409
17410    pub fn toggle_indent_guides(
17411        &mut self,
17412        _: &ToggleIndentGuides,
17413        _: &mut Window,
17414        cx: &mut Context<Self>,
17415    ) {
17416        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17417            self.buffer
17418                .read(cx)
17419                .language_settings(cx)
17420                .indent_guides
17421                .enabled
17422        });
17423        self.show_indent_guides = Some(!currently_enabled);
17424        cx.notify();
17425    }
17426
17427    fn should_show_indent_guides(&self) -> Option<bool> {
17428        self.show_indent_guides
17429    }
17430
17431    pub fn toggle_line_numbers(
17432        &mut self,
17433        _: &ToggleLineNumbers,
17434        _: &mut Window,
17435        cx: &mut Context<Self>,
17436    ) {
17437        let mut editor_settings = EditorSettings::get_global(cx).clone();
17438        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17439        EditorSettings::override_global(editor_settings, cx);
17440    }
17441
17442    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17443        if let Some(show_line_numbers) = self.show_line_numbers {
17444            return show_line_numbers;
17445        }
17446        EditorSettings::get_global(cx).gutter.line_numbers
17447    }
17448
17449    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17450        self.use_relative_line_numbers
17451            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17452    }
17453
17454    pub fn toggle_relative_line_numbers(
17455        &mut self,
17456        _: &ToggleRelativeLineNumbers,
17457        _: &mut Window,
17458        cx: &mut Context<Self>,
17459    ) {
17460        let is_relative = self.should_use_relative_line_numbers(cx);
17461        self.set_relative_line_number(Some(!is_relative), cx)
17462    }
17463
17464    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17465        self.use_relative_line_numbers = is_relative;
17466        cx.notify();
17467    }
17468
17469    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17470        self.show_gutter = show_gutter;
17471        cx.notify();
17472    }
17473
17474    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17475        self.show_scrollbars = ScrollbarAxes {
17476            horizontal: show,
17477            vertical: show,
17478        };
17479        cx.notify();
17480    }
17481
17482    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17483        self.show_scrollbars.vertical = show;
17484        cx.notify();
17485    }
17486
17487    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17488        self.show_scrollbars.horizontal = show;
17489        cx.notify();
17490    }
17491
17492    pub fn set_minimap_visibility(
17493        &mut self,
17494        minimap_visibility: MinimapVisibility,
17495        window: &mut Window,
17496        cx: &mut Context<Self>,
17497    ) {
17498        if self.minimap_visibility != minimap_visibility {
17499            if minimap_visibility.visible() && self.minimap.is_none() {
17500                let minimap_settings = EditorSettings::get_global(cx).minimap;
17501                self.minimap =
17502                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17503            }
17504            self.minimap_visibility = minimap_visibility;
17505            cx.notify();
17506        }
17507    }
17508
17509    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17510        self.set_show_scrollbars(false, cx);
17511        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17512    }
17513
17514    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17515        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17516    }
17517
17518    /// Normally the text in full mode and auto height editors is padded on the
17519    /// left side by roughly half a character width for improved hit testing.
17520    ///
17521    /// Use this method to disable this for cases where this is not wanted (e.g.
17522    /// if you want to align the editor text with some other text above or below)
17523    /// or if you want to add this padding to single-line editors.
17524    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17525        self.offset_content = offset_content;
17526        cx.notify();
17527    }
17528
17529    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17530        self.show_line_numbers = Some(show_line_numbers);
17531        cx.notify();
17532    }
17533
17534    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17535        self.disable_expand_excerpt_buttons = true;
17536        cx.notify();
17537    }
17538
17539    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17540        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17541        cx.notify();
17542    }
17543
17544    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17545        self.show_code_actions = Some(show_code_actions);
17546        cx.notify();
17547    }
17548
17549    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17550        self.show_runnables = Some(show_runnables);
17551        cx.notify();
17552    }
17553
17554    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17555        self.show_breakpoints = Some(show_breakpoints);
17556        cx.notify();
17557    }
17558
17559    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17560        if self.display_map.read(cx).masked != masked {
17561            self.display_map.update(cx, |map, _| map.masked = masked);
17562        }
17563        cx.notify()
17564    }
17565
17566    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17567        self.show_wrap_guides = Some(show_wrap_guides);
17568        cx.notify();
17569    }
17570
17571    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17572        self.show_indent_guides = Some(show_indent_guides);
17573        cx.notify();
17574    }
17575
17576    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17577        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17578            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17579                if let Some(dir) = file.abs_path(cx).parent() {
17580                    return Some(dir.to_owned());
17581                }
17582            }
17583
17584            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17585                return Some(project_path.path.to_path_buf());
17586            }
17587        }
17588
17589        None
17590    }
17591
17592    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17593        self.active_excerpt(cx)?
17594            .1
17595            .read(cx)
17596            .file()
17597            .and_then(|f| f.as_local())
17598    }
17599
17600    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17601        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17602            let buffer = buffer.read(cx);
17603            if let Some(project_path) = buffer.project_path(cx) {
17604                let project = self.project.as_ref()?.read(cx);
17605                project.absolute_path(&project_path, cx)
17606            } else {
17607                buffer
17608                    .file()
17609                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17610            }
17611        })
17612    }
17613
17614    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17615        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17616            let project_path = buffer.read(cx).project_path(cx)?;
17617            let project = self.project.as_ref()?.read(cx);
17618            let entry = project.entry_for_path(&project_path, cx)?;
17619            let path = entry.path.to_path_buf();
17620            Some(path)
17621        })
17622    }
17623
17624    pub fn reveal_in_finder(
17625        &mut self,
17626        _: &RevealInFileManager,
17627        _window: &mut Window,
17628        cx: &mut Context<Self>,
17629    ) {
17630        if let Some(target) = self.target_file(cx) {
17631            cx.reveal_path(&target.abs_path(cx));
17632        }
17633    }
17634
17635    pub fn copy_path(
17636        &mut self,
17637        _: &zed_actions::workspace::CopyPath,
17638        _window: &mut Window,
17639        cx: &mut Context<Self>,
17640    ) {
17641        if let Some(path) = self.target_file_abs_path(cx) {
17642            if let Some(path) = path.to_str() {
17643                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17644            }
17645        }
17646    }
17647
17648    pub fn copy_relative_path(
17649        &mut self,
17650        _: &zed_actions::workspace::CopyRelativePath,
17651        _window: &mut Window,
17652        cx: &mut Context<Self>,
17653    ) {
17654        if let Some(path) = self.target_file_path(cx) {
17655            if let Some(path) = path.to_str() {
17656                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17657            }
17658        }
17659    }
17660
17661    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17662        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17663            buffer.read(cx).project_path(cx)
17664        } else {
17665            None
17666        }
17667    }
17668
17669    // Returns true if the editor handled a go-to-line request
17670    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17671        maybe!({
17672            let breakpoint_store = self.breakpoint_store.as_ref()?;
17673
17674            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17675            else {
17676                self.clear_row_highlights::<ActiveDebugLine>();
17677                return None;
17678            };
17679
17680            let position = active_stack_frame.position;
17681            let buffer_id = position.buffer_id?;
17682            let snapshot = self
17683                .project
17684                .as_ref()?
17685                .read(cx)
17686                .buffer_for_id(buffer_id, cx)?
17687                .read(cx)
17688                .snapshot();
17689
17690            let mut handled = false;
17691            for (id, ExcerptRange { context, .. }) in
17692                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17693            {
17694                if context.start.cmp(&position, &snapshot).is_ge()
17695                    || context.end.cmp(&position, &snapshot).is_lt()
17696                {
17697                    continue;
17698                }
17699                let snapshot = self.buffer.read(cx).snapshot(cx);
17700                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17701
17702                handled = true;
17703                self.clear_row_highlights::<ActiveDebugLine>();
17704
17705                self.go_to_line::<ActiveDebugLine>(
17706                    multibuffer_anchor,
17707                    Some(cx.theme().colors().editor_debugger_active_line_background),
17708                    window,
17709                    cx,
17710                );
17711
17712                cx.notify();
17713            }
17714
17715            handled.then_some(())
17716        })
17717        .is_some()
17718    }
17719
17720    pub fn copy_file_name_without_extension(
17721        &mut self,
17722        _: &CopyFileNameWithoutExtension,
17723        _: &mut Window,
17724        cx: &mut Context<Self>,
17725    ) {
17726        if let Some(file) = self.target_file(cx) {
17727            if let Some(file_stem) = file.path().file_stem() {
17728                if let Some(name) = file_stem.to_str() {
17729                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17730                }
17731            }
17732        }
17733    }
17734
17735    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17736        if let Some(file) = self.target_file(cx) {
17737            if let Some(file_name) = file.path().file_name() {
17738                if let Some(name) = file_name.to_str() {
17739                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17740                }
17741            }
17742        }
17743    }
17744
17745    pub fn toggle_git_blame(
17746        &mut self,
17747        _: &::git::Blame,
17748        window: &mut Window,
17749        cx: &mut Context<Self>,
17750    ) {
17751        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17752
17753        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17754            self.start_git_blame(true, window, cx);
17755        }
17756
17757        cx.notify();
17758    }
17759
17760    pub fn toggle_git_blame_inline(
17761        &mut self,
17762        _: &ToggleGitBlameInline,
17763        window: &mut Window,
17764        cx: &mut Context<Self>,
17765    ) {
17766        self.toggle_git_blame_inline_internal(true, window, cx);
17767        cx.notify();
17768    }
17769
17770    pub fn open_git_blame_commit(
17771        &mut self,
17772        _: &OpenGitBlameCommit,
17773        window: &mut Window,
17774        cx: &mut Context<Self>,
17775    ) {
17776        self.open_git_blame_commit_internal(window, cx);
17777    }
17778
17779    fn open_git_blame_commit_internal(
17780        &mut self,
17781        window: &mut Window,
17782        cx: &mut Context<Self>,
17783    ) -> Option<()> {
17784        let blame = self.blame.as_ref()?;
17785        let snapshot = self.snapshot(window, cx);
17786        let cursor = self.selections.newest::<Point>(cx).head();
17787        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17788        let blame_entry = blame
17789            .update(cx, |blame, cx| {
17790                blame
17791                    .blame_for_rows(
17792                        &[RowInfo {
17793                            buffer_id: Some(buffer.remote_id()),
17794                            buffer_row: Some(point.row),
17795                            ..Default::default()
17796                        }],
17797                        cx,
17798                    )
17799                    .next()
17800            })
17801            .flatten()?;
17802        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17803        let repo = blame.read(cx).repository(cx)?;
17804        let workspace = self.workspace()?.downgrade();
17805        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17806        None
17807    }
17808
17809    pub fn git_blame_inline_enabled(&self) -> bool {
17810        self.git_blame_inline_enabled
17811    }
17812
17813    pub fn toggle_selection_menu(
17814        &mut self,
17815        _: &ToggleSelectionMenu,
17816        _: &mut Window,
17817        cx: &mut Context<Self>,
17818    ) {
17819        self.show_selection_menu = self
17820            .show_selection_menu
17821            .map(|show_selections_menu| !show_selections_menu)
17822            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17823
17824        cx.notify();
17825    }
17826
17827    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17828        self.show_selection_menu
17829            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17830    }
17831
17832    fn start_git_blame(
17833        &mut self,
17834        user_triggered: bool,
17835        window: &mut Window,
17836        cx: &mut Context<Self>,
17837    ) {
17838        if let Some(project) = self.project.as_ref() {
17839            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17840                return;
17841            };
17842
17843            if buffer.read(cx).file().is_none() {
17844                return;
17845            }
17846
17847            let focused = self.focus_handle(cx).contains_focused(window, cx);
17848
17849            let project = project.clone();
17850            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17851            self.blame_subscription =
17852                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17853            self.blame = Some(blame);
17854        }
17855    }
17856
17857    fn toggle_git_blame_inline_internal(
17858        &mut self,
17859        user_triggered: bool,
17860        window: &mut Window,
17861        cx: &mut Context<Self>,
17862    ) {
17863        if self.git_blame_inline_enabled {
17864            self.git_blame_inline_enabled = false;
17865            self.show_git_blame_inline = false;
17866            self.show_git_blame_inline_delay_task.take();
17867        } else {
17868            self.git_blame_inline_enabled = true;
17869            self.start_git_blame_inline(user_triggered, window, cx);
17870        }
17871
17872        cx.notify();
17873    }
17874
17875    fn start_git_blame_inline(
17876        &mut self,
17877        user_triggered: bool,
17878        window: &mut Window,
17879        cx: &mut Context<Self>,
17880    ) {
17881        self.start_git_blame(user_triggered, window, cx);
17882
17883        if ProjectSettings::get_global(cx)
17884            .git
17885            .inline_blame_delay()
17886            .is_some()
17887        {
17888            self.start_inline_blame_timer(window, cx);
17889        } else {
17890            self.show_git_blame_inline = true
17891        }
17892    }
17893
17894    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17895        self.blame.as_ref()
17896    }
17897
17898    pub fn show_git_blame_gutter(&self) -> bool {
17899        self.show_git_blame_gutter
17900    }
17901
17902    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17903        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17904    }
17905
17906    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17907        self.show_git_blame_inline
17908            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17909            && !self.newest_selection_head_on_empty_line(cx)
17910            && self.has_blame_entries(cx)
17911    }
17912
17913    fn has_blame_entries(&self, cx: &App) -> bool {
17914        self.blame()
17915            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17916    }
17917
17918    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17919        let cursor_anchor = self.selections.newest_anchor().head();
17920
17921        let snapshot = self.buffer.read(cx).snapshot(cx);
17922        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17923
17924        snapshot.line_len(buffer_row) == 0
17925    }
17926
17927    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17928        let buffer_and_selection = maybe!({
17929            let selection = self.selections.newest::<Point>(cx);
17930            let selection_range = selection.range();
17931
17932            let multi_buffer = self.buffer().read(cx);
17933            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17934            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17935
17936            let (buffer, range, _) = if selection.reversed {
17937                buffer_ranges.first()
17938            } else {
17939                buffer_ranges.last()
17940            }?;
17941
17942            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17943                ..text::ToPoint::to_point(&range.end, &buffer).row;
17944            Some((
17945                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17946                selection,
17947            ))
17948        });
17949
17950        let Some((buffer, selection)) = buffer_and_selection else {
17951            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17952        };
17953
17954        let Some(project) = self.project.as_ref() else {
17955            return Task::ready(Err(anyhow!("editor does not have project")));
17956        };
17957
17958        project.update(cx, |project, cx| {
17959            project.get_permalink_to_line(&buffer, selection, cx)
17960        })
17961    }
17962
17963    pub fn copy_permalink_to_line(
17964        &mut self,
17965        _: &CopyPermalinkToLine,
17966        window: &mut Window,
17967        cx: &mut Context<Self>,
17968    ) {
17969        let permalink_task = self.get_permalink_to_line(cx);
17970        let workspace = self.workspace();
17971
17972        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17973            Ok(permalink) => {
17974                cx.update(|_, cx| {
17975                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17976                })
17977                .ok();
17978            }
17979            Err(err) => {
17980                let message = format!("Failed to copy permalink: {err}");
17981
17982                anyhow::Result::<()>::Err(err).log_err();
17983
17984                if let Some(workspace) = workspace {
17985                    workspace
17986                        .update_in(cx, |workspace, _, cx| {
17987                            struct CopyPermalinkToLine;
17988
17989                            workspace.show_toast(
17990                                Toast::new(
17991                                    NotificationId::unique::<CopyPermalinkToLine>(),
17992                                    message,
17993                                ),
17994                                cx,
17995                            )
17996                        })
17997                        .ok();
17998                }
17999            }
18000        })
18001        .detach();
18002    }
18003
18004    pub fn copy_file_location(
18005        &mut self,
18006        _: &CopyFileLocation,
18007        _: &mut Window,
18008        cx: &mut Context<Self>,
18009    ) {
18010        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18011        if let Some(file) = self.target_file(cx) {
18012            if let Some(path) = file.path().to_str() {
18013                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18014            }
18015        }
18016    }
18017
18018    pub fn open_permalink_to_line(
18019        &mut self,
18020        _: &OpenPermalinkToLine,
18021        window: &mut Window,
18022        cx: &mut Context<Self>,
18023    ) {
18024        let permalink_task = self.get_permalink_to_line(cx);
18025        let workspace = self.workspace();
18026
18027        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18028            Ok(permalink) => {
18029                cx.update(|_, cx| {
18030                    cx.open_url(permalink.as_ref());
18031                })
18032                .ok();
18033            }
18034            Err(err) => {
18035                let message = format!("Failed to open permalink: {err}");
18036
18037                anyhow::Result::<()>::Err(err).log_err();
18038
18039                if let Some(workspace) = workspace {
18040                    workspace
18041                        .update(cx, |workspace, cx| {
18042                            struct OpenPermalinkToLine;
18043
18044                            workspace.show_toast(
18045                                Toast::new(
18046                                    NotificationId::unique::<OpenPermalinkToLine>(),
18047                                    message,
18048                                ),
18049                                cx,
18050                            )
18051                        })
18052                        .ok();
18053                }
18054            }
18055        })
18056        .detach();
18057    }
18058
18059    pub fn insert_uuid_v4(
18060        &mut self,
18061        _: &InsertUuidV4,
18062        window: &mut Window,
18063        cx: &mut Context<Self>,
18064    ) {
18065        self.insert_uuid(UuidVersion::V4, window, cx);
18066    }
18067
18068    pub fn insert_uuid_v7(
18069        &mut self,
18070        _: &InsertUuidV7,
18071        window: &mut Window,
18072        cx: &mut Context<Self>,
18073    ) {
18074        self.insert_uuid(UuidVersion::V7, window, cx);
18075    }
18076
18077    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18078        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18079        self.transact(window, cx, |this, window, cx| {
18080            let edits = this
18081                .selections
18082                .all::<Point>(cx)
18083                .into_iter()
18084                .map(|selection| {
18085                    let uuid = match version {
18086                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18087                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18088                    };
18089
18090                    (selection.range(), uuid.to_string())
18091                });
18092            this.edit(edits, cx);
18093            this.refresh_inline_completion(true, false, window, cx);
18094        });
18095    }
18096
18097    pub fn open_selections_in_multibuffer(
18098        &mut self,
18099        _: &OpenSelectionsInMultibuffer,
18100        window: &mut Window,
18101        cx: &mut Context<Self>,
18102    ) {
18103        let multibuffer = self.buffer.read(cx);
18104
18105        let Some(buffer) = multibuffer.as_singleton() else {
18106            return;
18107        };
18108
18109        let Some(workspace) = self.workspace() else {
18110            return;
18111        };
18112
18113        let locations = self
18114            .selections
18115            .disjoint_anchors()
18116            .iter()
18117            .map(|selection| {
18118                let range = if selection.reversed {
18119                    selection.end.text_anchor..selection.start.text_anchor
18120                } else {
18121                    selection.start.text_anchor..selection.end.text_anchor
18122                };
18123                Location {
18124                    buffer: buffer.clone(),
18125                    range,
18126                }
18127            })
18128            .collect::<Vec<_>>();
18129
18130        let title = multibuffer.title(cx).to_string();
18131
18132        cx.spawn_in(window, async move |_, cx| {
18133            workspace.update_in(cx, |workspace, window, cx| {
18134                Self::open_locations_in_multibuffer(
18135                    workspace,
18136                    locations,
18137                    format!("Selections for '{title}'"),
18138                    false,
18139                    MultibufferSelectionMode::All,
18140                    window,
18141                    cx,
18142                );
18143            })
18144        })
18145        .detach();
18146    }
18147
18148    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18149    /// last highlight added will be used.
18150    ///
18151    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18152    pub fn highlight_rows<T: 'static>(
18153        &mut self,
18154        range: Range<Anchor>,
18155        color: Hsla,
18156        options: RowHighlightOptions,
18157        cx: &mut Context<Self>,
18158    ) {
18159        let snapshot = self.buffer().read(cx).snapshot(cx);
18160        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18161        let ix = row_highlights.binary_search_by(|highlight| {
18162            Ordering::Equal
18163                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18164                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18165        });
18166
18167        if let Err(mut ix) = ix {
18168            let index = post_inc(&mut self.highlight_order);
18169
18170            // If this range intersects with the preceding highlight, then merge it with
18171            // the preceding highlight. Otherwise insert a new highlight.
18172            let mut merged = false;
18173            if ix > 0 {
18174                let prev_highlight = &mut row_highlights[ix - 1];
18175                if prev_highlight
18176                    .range
18177                    .end
18178                    .cmp(&range.start, &snapshot)
18179                    .is_ge()
18180                {
18181                    ix -= 1;
18182                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18183                        prev_highlight.range.end = range.end;
18184                    }
18185                    merged = true;
18186                    prev_highlight.index = index;
18187                    prev_highlight.color = color;
18188                    prev_highlight.options = options;
18189                }
18190            }
18191
18192            if !merged {
18193                row_highlights.insert(
18194                    ix,
18195                    RowHighlight {
18196                        range: range.clone(),
18197                        index,
18198                        color,
18199                        options,
18200                        type_id: TypeId::of::<T>(),
18201                    },
18202                );
18203            }
18204
18205            // If any of the following highlights intersect with this one, merge them.
18206            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18207                let highlight = &row_highlights[ix];
18208                if next_highlight
18209                    .range
18210                    .start
18211                    .cmp(&highlight.range.end, &snapshot)
18212                    .is_le()
18213                {
18214                    if next_highlight
18215                        .range
18216                        .end
18217                        .cmp(&highlight.range.end, &snapshot)
18218                        .is_gt()
18219                    {
18220                        row_highlights[ix].range.end = next_highlight.range.end;
18221                    }
18222                    row_highlights.remove(ix + 1);
18223                } else {
18224                    break;
18225                }
18226            }
18227        }
18228    }
18229
18230    /// Remove any highlighted row ranges of the given type that intersect the
18231    /// given ranges.
18232    pub fn remove_highlighted_rows<T: 'static>(
18233        &mut self,
18234        ranges_to_remove: Vec<Range<Anchor>>,
18235        cx: &mut Context<Self>,
18236    ) {
18237        let snapshot = self.buffer().read(cx).snapshot(cx);
18238        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18239        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18240        row_highlights.retain(|highlight| {
18241            while let Some(range_to_remove) = ranges_to_remove.peek() {
18242                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18243                    Ordering::Less | Ordering::Equal => {
18244                        ranges_to_remove.next();
18245                    }
18246                    Ordering::Greater => {
18247                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18248                            Ordering::Less | Ordering::Equal => {
18249                                return false;
18250                            }
18251                            Ordering::Greater => break,
18252                        }
18253                    }
18254                }
18255            }
18256
18257            true
18258        })
18259    }
18260
18261    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18262    pub fn clear_row_highlights<T: 'static>(&mut self) {
18263        self.highlighted_rows.remove(&TypeId::of::<T>());
18264    }
18265
18266    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18267    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18268        self.highlighted_rows
18269            .get(&TypeId::of::<T>())
18270            .map_or(&[] as &[_], |vec| vec.as_slice())
18271            .iter()
18272            .map(|highlight| (highlight.range.clone(), highlight.color))
18273    }
18274
18275    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18276    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18277    /// Allows to ignore certain kinds of highlights.
18278    pub fn highlighted_display_rows(
18279        &self,
18280        window: &mut Window,
18281        cx: &mut App,
18282    ) -> BTreeMap<DisplayRow, LineHighlight> {
18283        let snapshot = self.snapshot(window, cx);
18284        let mut used_highlight_orders = HashMap::default();
18285        self.highlighted_rows
18286            .iter()
18287            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18288            .fold(
18289                BTreeMap::<DisplayRow, LineHighlight>::new(),
18290                |mut unique_rows, highlight| {
18291                    let start = highlight.range.start.to_display_point(&snapshot);
18292                    let end = highlight.range.end.to_display_point(&snapshot);
18293                    let start_row = start.row().0;
18294                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18295                        && end.column() == 0
18296                    {
18297                        end.row().0.saturating_sub(1)
18298                    } else {
18299                        end.row().0
18300                    };
18301                    for row in start_row..=end_row {
18302                        let used_index =
18303                            used_highlight_orders.entry(row).or_insert(highlight.index);
18304                        if highlight.index >= *used_index {
18305                            *used_index = highlight.index;
18306                            unique_rows.insert(
18307                                DisplayRow(row),
18308                                LineHighlight {
18309                                    include_gutter: highlight.options.include_gutter,
18310                                    border: None,
18311                                    background: highlight.color.into(),
18312                                    type_id: Some(highlight.type_id),
18313                                },
18314                            );
18315                        }
18316                    }
18317                    unique_rows
18318                },
18319            )
18320    }
18321
18322    pub fn highlighted_display_row_for_autoscroll(
18323        &self,
18324        snapshot: &DisplaySnapshot,
18325    ) -> Option<DisplayRow> {
18326        self.highlighted_rows
18327            .values()
18328            .flat_map(|highlighted_rows| highlighted_rows.iter())
18329            .filter_map(|highlight| {
18330                if highlight.options.autoscroll {
18331                    Some(highlight.range.start.to_display_point(snapshot).row())
18332                } else {
18333                    None
18334                }
18335            })
18336            .min()
18337    }
18338
18339    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18340        self.highlight_background::<SearchWithinRange>(
18341            ranges,
18342            |colors| colors.editor_document_highlight_read_background,
18343            cx,
18344        )
18345    }
18346
18347    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18348        self.breadcrumb_header = Some(new_header);
18349    }
18350
18351    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18352        self.clear_background_highlights::<SearchWithinRange>(cx);
18353    }
18354
18355    pub fn highlight_background<T: 'static>(
18356        &mut self,
18357        ranges: &[Range<Anchor>],
18358        color_fetcher: fn(&ThemeColors) -> Hsla,
18359        cx: &mut Context<Self>,
18360    ) {
18361        self.background_highlights
18362            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18363        self.scrollbar_marker_state.dirty = true;
18364        cx.notify();
18365    }
18366
18367    pub fn clear_background_highlights<T: 'static>(
18368        &mut self,
18369        cx: &mut Context<Self>,
18370    ) -> Option<BackgroundHighlight> {
18371        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18372        if !text_highlights.1.is_empty() {
18373            self.scrollbar_marker_state.dirty = true;
18374            cx.notify();
18375        }
18376        Some(text_highlights)
18377    }
18378
18379    pub fn highlight_gutter<T: 'static>(
18380        &mut self,
18381        ranges: impl Into<Vec<Range<Anchor>>>,
18382        color_fetcher: fn(&App) -> Hsla,
18383        cx: &mut Context<Self>,
18384    ) {
18385        self.gutter_highlights
18386            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18387        cx.notify();
18388    }
18389
18390    pub fn clear_gutter_highlights<T: 'static>(
18391        &mut self,
18392        cx: &mut Context<Self>,
18393    ) -> Option<GutterHighlight> {
18394        cx.notify();
18395        self.gutter_highlights.remove(&TypeId::of::<T>())
18396    }
18397
18398    pub fn insert_gutter_highlight<T: 'static>(
18399        &mut self,
18400        range: Range<Anchor>,
18401        color_fetcher: fn(&App) -> Hsla,
18402        cx: &mut Context<Self>,
18403    ) {
18404        let snapshot = self.buffer().read(cx).snapshot(cx);
18405        let mut highlights = self
18406            .gutter_highlights
18407            .remove(&TypeId::of::<T>())
18408            .map(|(_, highlights)| highlights)
18409            .unwrap_or_default();
18410        let ix = highlights.binary_search_by(|highlight| {
18411            Ordering::Equal
18412                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18413                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18414        });
18415        if let Err(ix) = ix {
18416            highlights.insert(ix, range);
18417        }
18418        self.gutter_highlights
18419            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18420    }
18421
18422    pub fn remove_gutter_highlights<T: 'static>(
18423        &mut self,
18424        ranges_to_remove: Vec<Range<Anchor>>,
18425        cx: &mut Context<Self>,
18426    ) {
18427        let snapshot = self.buffer().read(cx).snapshot(cx);
18428        let Some((color_fetcher, mut gutter_highlights)) =
18429            self.gutter_highlights.remove(&TypeId::of::<T>())
18430        else {
18431            return;
18432        };
18433        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18434        gutter_highlights.retain(|highlight| {
18435            while let Some(range_to_remove) = ranges_to_remove.peek() {
18436                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18437                    Ordering::Less | Ordering::Equal => {
18438                        ranges_to_remove.next();
18439                    }
18440                    Ordering::Greater => {
18441                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18442                            Ordering::Less | Ordering::Equal => {
18443                                return false;
18444                            }
18445                            Ordering::Greater => break,
18446                        }
18447                    }
18448                }
18449            }
18450
18451            true
18452        });
18453        self.gutter_highlights
18454            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18455    }
18456
18457    #[cfg(feature = "test-support")]
18458    pub fn all_text_background_highlights(
18459        &self,
18460        window: &mut Window,
18461        cx: &mut Context<Self>,
18462    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18463        let snapshot = self.snapshot(window, cx);
18464        let buffer = &snapshot.buffer_snapshot;
18465        let start = buffer.anchor_before(0);
18466        let end = buffer.anchor_after(buffer.len());
18467        let theme = cx.theme().colors();
18468        self.background_highlights_in_range(start..end, &snapshot, theme)
18469    }
18470
18471    #[cfg(feature = "test-support")]
18472    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18473        let snapshot = self.buffer().read(cx).snapshot(cx);
18474
18475        let highlights = self
18476            .background_highlights
18477            .get(&TypeId::of::<items::BufferSearchHighlights>());
18478
18479        if let Some((_color, ranges)) = highlights {
18480            ranges
18481                .iter()
18482                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18483                .collect_vec()
18484        } else {
18485            vec![]
18486        }
18487    }
18488
18489    fn document_highlights_for_position<'a>(
18490        &'a self,
18491        position: Anchor,
18492        buffer: &'a MultiBufferSnapshot,
18493    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18494        let read_highlights = self
18495            .background_highlights
18496            .get(&TypeId::of::<DocumentHighlightRead>())
18497            .map(|h| &h.1);
18498        let write_highlights = self
18499            .background_highlights
18500            .get(&TypeId::of::<DocumentHighlightWrite>())
18501            .map(|h| &h.1);
18502        let left_position = position.bias_left(buffer);
18503        let right_position = position.bias_right(buffer);
18504        read_highlights
18505            .into_iter()
18506            .chain(write_highlights)
18507            .flat_map(move |ranges| {
18508                let start_ix = match ranges.binary_search_by(|probe| {
18509                    let cmp = probe.end.cmp(&left_position, buffer);
18510                    if cmp.is_ge() {
18511                        Ordering::Greater
18512                    } else {
18513                        Ordering::Less
18514                    }
18515                }) {
18516                    Ok(i) | Err(i) => i,
18517                };
18518
18519                ranges[start_ix..]
18520                    .iter()
18521                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18522            })
18523    }
18524
18525    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18526        self.background_highlights
18527            .get(&TypeId::of::<T>())
18528            .map_or(false, |(_, highlights)| !highlights.is_empty())
18529    }
18530
18531    pub fn background_highlights_in_range(
18532        &self,
18533        search_range: Range<Anchor>,
18534        display_snapshot: &DisplaySnapshot,
18535        theme: &ThemeColors,
18536    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18537        let mut results = Vec::new();
18538        for (color_fetcher, ranges) in self.background_highlights.values() {
18539            let color = color_fetcher(theme);
18540            let start_ix = match ranges.binary_search_by(|probe| {
18541                let cmp = probe
18542                    .end
18543                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18544                if cmp.is_gt() {
18545                    Ordering::Greater
18546                } else {
18547                    Ordering::Less
18548                }
18549            }) {
18550                Ok(i) | Err(i) => i,
18551            };
18552            for range in &ranges[start_ix..] {
18553                if range
18554                    .start
18555                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18556                    .is_ge()
18557                {
18558                    break;
18559                }
18560
18561                let start = range.start.to_display_point(display_snapshot);
18562                let end = range.end.to_display_point(display_snapshot);
18563                results.push((start..end, color))
18564            }
18565        }
18566        results
18567    }
18568
18569    pub fn background_highlight_row_ranges<T: 'static>(
18570        &self,
18571        search_range: Range<Anchor>,
18572        display_snapshot: &DisplaySnapshot,
18573        count: usize,
18574    ) -> Vec<RangeInclusive<DisplayPoint>> {
18575        let mut results = Vec::new();
18576        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18577            return vec![];
18578        };
18579
18580        let start_ix = match ranges.binary_search_by(|probe| {
18581            let cmp = probe
18582                .end
18583                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18584            if cmp.is_gt() {
18585                Ordering::Greater
18586            } else {
18587                Ordering::Less
18588            }
18589        }) {
18590            Ok(i) | Err(i) => i,
18591        };
18592        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18593            if let (Some(start_display), Some(end_display)) = (start, end) {
18594                results.push(
18595                    start_display.to_display_point(display_snapshot)
18596                        ..=end_display.to_display_point(display_snapshot),
18597                );
18598            }
18599        };
18600        let mut start_row: Option<Point> = None;
18601        let mut end_row: Option<Point> = None;
18602        if ranges.len() > count {
18603            return Vec::new();
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            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18614            if let Some(current_row) = &end_row {
18615                if end.row == current_row.row {
18616                    continue;
18617                }
18618            }
18619            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18620            if start_row.is_none() {
18621                assert_eq!(end_row, None);
18622                start_row = Some(start);
18623                end_row = Some(end);
18624                continue;
18625            }
18626            if let Some(current_end) = end_row.as_mut() {
18627                if start.row > current_end.row + 1 {
18628                    push_region(start_row, end_row);
18629                    start_row = Some(start);
18630                    end_row = Some(end);
18631                } else {
18632                    // Merge two hunks.
18633                    *current_end = end;
18634                }
18635            } else {
18636                unreachable!();
18637            }
18638        }
18639        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18640        push_region(start_row, end_row);
18641        results
18642    }
18643
18644    pub fn gutter_highlights_in_range(
18645        &self,
18646        search_range: Range<Anchor>,
18647        display_snapshot: &DisplaySnapshot,
18648        cx: &App,
18649    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18650        let mut results = Vec::new();
18651        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18652            let color = color_fetcher(cx);
18653            let start_ix = match ranges.binary_search_by(|probe| {
18654                let cmp = probe
18655                    .end
18656                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18657                if cmp.is_gt() {
18658                    Ordering::Greater
18659                } else {
18660                    Ordering::Less
18661                }
18662            }) {
18663                Ok(i) | Err(i) => i,
18664            };
18665            for range in &ranges[start_ix..] {
18666                if range
18667                    .start
18668                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18669                    .is_ge()
18670                {
18671                    break;
18672                }
18673
18674                let start = range.start.to_display_point(display_snapshot);
18675                let end = range.end.to_display_point(display_snapshot);
18676                results.push((start..end, color))
18677            }
18678        }
18679        results
18680    }
18681
18682    /// Get the text ranges corresponding to the redaction query
18683    pub fn redacted_ranges(
18684        &self,
18685        search_range: Range<Anchor>,
18686        display_snapshot: &DisplaySnapshot,
18687        cx: &App,
18688    ) -> Vec<Range<DisplayPoint>> {
18689        display_snapshot
18690            .buffer_snapshot
18691            .redacted_ranges(search_range, |file| {
18692                if let Some(file) = file {
18693                    file.is_private()
18694                        && EditorSettings::get(
18695                            Some(SettingsLocation {
18696                                worktree_id: file.worktree_id(cx),
18697                                path: file.path().as_ref(),
18698                            }),
18699                            cx,
18700                        )
18701                        .redact_private_values
18702                } else {
18703                    false
18704                }
18705            })
18706            .map(|range| {
18707                range.start.to_display_point(display_snapshot)
18708                    ..range.end.to_display_point(display_snapshot)
18709            })
18710            .collect()
18711    }
18712
18713    pub fn highlight_text<T: 'static>(
18714        &mut self,
18715        ranges: Vec<Range<Anchor>>,
18716        style: HighlightStyle,
18717        cx: &mut Context<Self>,
18718    ) {
18719        self.display_map.update(cx, |map, _| {
18720            map.highlight_text(TypeId::of::<T>(), ranges, style)
18721        });
18722        cx.notify();
18723    }
18724
18725    pub(crate) fn highlight_inlays<T: 'static>(
18726        &mut self,
18727        highlights: Vec<InlayHighlight>,
18728        style: HighlightStyle,
18729        cx: &mut Context<Self>,
18730    ) {
18731        self.display_map.update(cx, |map, _| {
18732            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18733        });
18734        cx.notify();
18735    }
18736
18737    pub fn text_highlights<'a, T: 'static>(
18738        &'a self,
18739        cx: &'a App,
18740    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18741        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18742    }
18743
18744    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18745        let cleared = self
18746            .display_map
18747            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18748        if cleared {
18749            cx.notify();
18750        }
18751    }
18752
18753    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18754        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18755            && self.focus_handle.is_focused(window)
18756    }
18757
18758    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18759        self.show_cursor_when_unfocused = is_enabled;
18760        cx.notify();
18761    }
18762
18763    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18764        cx.notify();
18765    }
18766
18767    fn on_debug_session_event(
18768        &mut self,
18769        _session: Entity<Session>,
18770        event: &SessionEvent,
18771        cx: &mut Context<Self>,
18772    ) {
18773        match event {
18774            SessionEvent::InvalidateInlineValue => {
18775                self.refresh_inline_values(cx);
18776            }
18777            _ => {}
18778        }
18779    }
18780
18781    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18782        let Some(project) = self.project.clone() else {
18783            return;
18784        };
18785
18786        if !self.inline_value_cache.enabled {
18787            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18788            self.splice_inlays(&inlays, Vec::new(), cx);
18789            return;
18790        }
18791
18792        let current_execution_position = self
18793            .highlighted_rows
18794            .get(&TypeId::of::<ActiveDebugLine>())
18795            .and_then(|lines| lines.last().map(|line| line.range.start));
18796
18797        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18798            let inline_values = editor
18799                .update(cx, |editor, cx| {
18800                    let Some(current_execution_position) = current_execution_position else {
18801                        return Some(Task::ready(Ok(Vec::new())));
18802                    };
18803
18804                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18805                        let snapshot = buffer.snapshot(cx);
18806
18807                        let excerpt = snapshot.excerpt_containing(
18808                            current_execution_position..current_execution_position,
18809                        )?;
18810
18811                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18812                    })?;
18813
18814                    let range =
18815                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18816
18817                    project.inline_values(buffer, range, cx)
18818                })
18819                .ok()
18820                .flatten()?
18821                .await
18822                .context("refreshing debugger inlays")
18823                .log_err()?;
18824
18825            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18826
18827            for (buffer_id, inline_value) in inline_values
18828                .into_iter()
18829                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18830            {
18831                buffer_inline_values
18832                    .entry(buffer_id)
18833                    .or_default()
18834                    .push(inline_value);
18835            }
18836
18837            editor
18838                .update(cx, |editor, cx| {
18839                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18840                    let mut new_inlays = Vec::default();
18841
18842                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18843                        let buffer_id = buffer_snapshot.remote_id();
18844                        buffer_inline_values
18845                            .get(&buffer_id)
18846                            .into_iter()
18847                            .flatten()
18848                            .for_each(|hint| {
18849                                let inlay = Inlay::debugger_hint(
18850                                    post_inc(&mut editor.next_inlay_id),
18851                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18852                                    hint.text(),
18853                                );
18854
18855                                new_inlays.push(inlay);
18856                            });
18857                    }
18858
18859                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18860                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18861
18862                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18863                })
18864                .ok()?;
18865            Some(())
18866        });
18867    }
18868
18869    fn on_buffer_event(
18870        &mut self,
18871        multibuffer: &Entity<MultiBuffer>,
18872        event: &multi_buffer::Event,
18873        window: &mut Window,
18874        cx: &mut Context<Self>,
18875    ) {
18876        match event {
18877            multi_buffer::Event::Edited {
18878                singleton_buffer_edited,
18879                edited_buffer,
18880            } => {
18881                self.scrollbar_marker_state.dirty = true;
18882                self.active_indent_guides_state.dirty = true;
18883                self.refresh_active_diagnostics(cx);
18884                self.refresh_code_actions(window, cx);
18885                self.refresh_selected_text_highlights(true, window, cx);
18886                refresh_matching_bracket_highlights(self, window, cx);
18887                if self.has_active_inline_completion() {
18888                    self.update_visible_inline_completion(window, cx);
18889                }
18890                if let Some(project) = self.project.as_ref() {
18891                    if let Some(edited_buffer) = edited_buffer {
18892                        project.update(cx, |project, cx| {
18893                            self.registered_buffers
18894                                .entry(edited_buffer.read(cx).remote_id())
18895                                .or_insert_with(|| {
18896                                    project
18897                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18898                                });
18899                        });
18900                        if edited_buffer.read(cx).file().is_some() {
18901                            self.pull_diagnostics(
18902                                Some(edited_buffer.read(cx).remote_id()),
18903                                window,
18904                                cx,
18905                            );
18906                        }
18907                    }
18908                }
18909                cx.emit(EditorEvent::BufferEdited);
18910                cx.emit(SearchEvent::MatchesInvalidated);
18911                if *singleton_buffer_edited {
18912                    if let Some(buffer) = edited_buffer {
18913                        if buffer.read(cx).file().is_none() {
18914                            cx.emit(EditorEvent::TitleChanged);
18915                        }
18916                    }
18917                    if let Some(project) = &self.project {
18918                        #[allow(clippy::mutable_key_type)]
18919                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18920                            multibuffer
18921                                .all_buffers()
18922                                .into_iter()
18923                                .filter_map(|buffer| {
18924                                    buffer.update(cx, |buffer, cx| {
18925                                        let language = buffer.language()?;
18926                                        let should_discard = project.update(cx, |project, cx| {
18927                                            project.is_local()
18928                                                && !project.has_language_servers_for(buffer, cx)
18929                                        });
18930                                        should_discard.not().then_some(language.clone())
18931                                    })
18932                                })
18933                                .collect::<HashSet<_>>()
18934                        });
18935                        if !languages_affected.is_empty() {
18936                            self.refresh_inlay_hints(
18937                                InlayHintRefreshReason::BufferEdited(languages_affected),
18938                                cx,
18939                            );
18940                        }
18941                    }
18942                }
18943
18944                let Some(project) = &self.project else { return };
18945                let (telemetry, is_via_ssh) = {
18946                    let project = project.read(cx);
18947                    let telemetry = project.client().telemetry().clone();
18948                    let is_via_ssh = project.is_via_ssh();
18949                    (telemetry, is_via_ssh)
18950                };
18951                refresh_linked_ranges(self, window, cx);
18952                telemetry.log_edit_event("editor", is_via_ssh);
18953            }
18954            multi_buffer::Event::ExcerptsAdded {
18955                buffer,
18956                predecessor,
18957                excerpts,
18958            } => {
18959                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18960                let buffer_id = buffer.read(cx).remote_id();
18961                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18962                    if let Some(project) = &self.project {
18963                        update_uncommitted_diff_for_buffer(
18964                            cx.entity(),
18965                            project,
18966                            [buffer.clone()],
18967                            self.buffer.clone(),
18968                            cx,
18969                        )
18970                        .detach();
18971                    }
18972                }
18973                cx.emit(EditorEvent::ExcerptsAdded {
18974                    buffer: buffer.clone(),
18975                    predecessor: *predecessor,
18976                    excerpts: excerpts.clone(),
18977                });
18978                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18979            }
18980            multi_buffer::Event::ExcerptsRemoved {
18981                ids,
18982                removed_buffer_ids,
18983            } => {
18984                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18985                let buffer = self.buffer.read(cx);
18986                self.registered_buffers
18987                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18988                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18989                cx.emit(EditorEvent::ExcerptsRemoved {
18990                    ids: ids.clone(),
18991                    removed_buffer_ids: removed_buffer_ids.clone(),
18992                })
18993            }
18994            multi_buffer::Event::ExcerptsEdited {
18995                excerpt_ids,
18996                buffer_ids,
18997            } => {
18998                self.display_map.update(cx, |map, cx| {
18999                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19000                });
19001                cx.emit(EditorEvent::ExcerptsEdited {
19002                    ids: excerpt_ids.clone(),
19003                })
19004            }
19005            multi_buffer::Event::ExcerptsExpanded { ids } => {
19006                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19007                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19008            }
19009            multi_buffer::Event::Reparsed(buffer_id) => {
19010                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19011                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19012
19013                cx.emit(EditorEvent::Reparsed(*buffer_id));
19014            }
19015            multi_buffer::Event::DiffHunksToggled => {
19016                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19017            }
19018            multi_buffer::Event::LanguageChanged(buffer_id) => {
19019                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19020                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19021                cx.emit(EditorEvent::Reparsed(*buffer_id));
19022                cx.notify();
19023            }
19024            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19025            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19026            multi_buffer::Event::FileHandleChanged
19027            | multi_buffer::Event::Reloaded
19028            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19029            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19030            multi_buffer::Event::DiagnosticsUpdated => {
19031                self.update_diagnostics_state(window, cx);
19032            }
19033            _ => {}
19034        };
19035    }
19036
19037    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19038        self.refresh_active_diagnostics(cx);
19039        self.refresh_inline_diagnostics(true, window, cx);
19040        self.scrollbar_marker_state.dirty = true;
19041        cx.notify();
19042    }
19043
19044    pub fn start_temporary_diff_override(&mut self) {
19045        self.load_diff_task.take();
19046        self.temporary_diff_override = true;
19047    }
19048
19049    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19050        self.temporary_diff_override = false;
19051        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19052        self.buffer.update(cx, |buffer, cx| {
19053            buffer.set_all_diff_hunks_collapsed(cx);
19054        });
19055
19056        if let Some(project) = self.project.clone() {
19057            self.load_diff_task = Some(
19058                update_uncommitted_diff_for_buffer(
19059                    cx.entity(),
19060                    &project,
19061                    self.buffer.read(cx).all_buffers(),
19062                    self.buffer.clone(),
19063                    cx,
19064                )
19065                .shared(),
19066            );
19067        }
19068    }
19069
19070    fn on_display_map_changed(
19071        &mut self,
19072        _: Entity<DisplayMap>,
19073        _: &mut Window,
19074        cx: &mut Context<Self>,
19075    ) {
19076        cx.notify();
19077    }
19078
19079    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19080        let new_severity = if self.diagnostics_enabled() {
19081            EditorSettings::get_global(cx)
19082                .diagnostics_max_severity
19083                .unwrap_or(DiagnosticSeverity::Hint)
19084        } else {
19085            DiagnosticSeverity::Off
19086        };
19087        self.set_max_diagnostics_severity(new_severity, cx);
19088        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19089        self.update_edit_prediction_settings(cx);
19090        self.refresh_inline_completion(true, false, window, cx);
19091        self.refresh_inlay_hints(
19092            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19093                self.selections.newest_anchor().head(),
19094                &self.buffer.read(cx).snapshot(cx),
19095                cx,
19096            )),
19097            cx,
19098        );
19099
19100        let old_cursor_shape = self.cursor_shape;
19101
19102        {
19103            let editor_settings = EditorSettings::get_global(cx);
19104            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19105            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19106            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19107            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19108            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19109        }
19110
19111        if old_cursor_shape != self.cursor_shape {
19112            cx.emit(EditorEvent::CursorShapeChanged);
19113        }
19114
19115        let project_settings = ProjectSettings::get_global(cx);
19116        self.serialize_dirty_buffers =
19117            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19118
19119        if self.mode.is_full() {
19120            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19121            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19122            if self.show_inline_diagnostics != show_inline_diagnostics {
19123                self.show_inline_diagnostics = show_inline_diagnostics;
19124                self.refresh_inline_diagnostics(false, window, cx);
19125            }
19126
19127            if self.git_blame_inline_enabled != inline_blame_enabled {
19128                self.toggle_git_blame_inline_internal(false, window, cx);
19129            }
19130
19131            let minimap_settings = EditorSettings::get_global(cx).minimap;
19132            if self.minimap_visibility != MinimapVisibility::Disabled {
19133                if self.minimap_visibility.settings_visibility()
19134                    != minimap_settings.minimap_enabled()
19135                {
19136                    self.set_minimap_visibility(
19137                        MinimapVisibility::for_mode(self.mode(), cx),
19138                        window,
19139                        cx,
19140                    );
19141                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19142                    minimap_entity.update(cx, |minimap_editor, cx| {
19143                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19144                    })
19145                }
19146            }
19147        }
19148
19149        cx.notify();
19150    }
19151
19152    pub fn set_searchable(&mut self, searchable: bool) {
19153        self.searchable = searchable;
19154    }
19155
19156    pub fn searchable(&self) -> bool {
19157        self.searchable
19158    }
19159
19160    fn open_proposed_changes_editor(
19161        &mut self,
19162        _: &OpenProposedChangesEditor,
19163        window: &mut Window,
19164        cx: &mut Context<Self>,
19165    ) {
19166        let Some(workspace) = self.workspace() else {
19167            cx.propagate();
19168            return;
19169        };
19170
19171        let selections = self.selections.all::<usize>(cx);
19172        let multi_buffer = self.buffer.read(cx);
19173        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19174        let mut new_selections_by_buffer = HashMap::default();
19175        for selection in selections {
19176            for (buffer, range, _) in
19177                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19178            {
19179                let mut range = range.to_point(buffer);
19180                range.start.column = 0;
19181                range.end.column = buffer.line_len(range.end.row);
19182                new_selections_by_buffer
19183                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19184                    .or_insert(Vec::new())
19185                    .push(range)
19186            }
19187        }
19188
19189        let proposed_changes_buffers = new_selections_by_buffer
19190            .into_iter()
19191            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19192            .collect::<Vec<_>>();
19193        let proposed_changes_editor = cx.new(|cx| {
19194            ProposedChangesEditor::new(
19195                "Proposed changes",
19196                proposed_changes_buffers,
19197                self.project.clone(),
19198                window,
19199                cx,
19200            )
19201        });
19202
19203        window.defer(cx, move |window, cx| {
19204            workspace.update(cx, |workspace, cx| {
19205                workspace.active_pane().update(cx, |pane, cx| {
19206                    pane.add_item(
19207                        Box::new(proposed_changes_editor),
19208                        true,
19209                        true,
19210                        None,
19211                        window,
19212                        cx,
19213                    );
19214                });
19215            });
19216        });
19217    }
19218
19219    pub fn open_excerpts_in_split(
19220        &mut self,
19221        _: &OpenExcerptsSplit,
19222        window: &mut Window,
19223        cx: &mut Context<Self>,
19224    ) {
19225        self.open_excerpts_common(None, true, window, cx)
19226    }
19227
19228    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19229        self.open_excerpts_common(None, false, window, cx)
19230    }
19231
19232    fn open_excerpts_common(
19233        &mut self,
19234        jump_data: Option<JumpData>,
19235        split: bool,
19236        window: &mut Window,
19237        cx: &mut Context<Self>,
19238    ) {
19239        let Some(workspace) = self.workspace() else {
19240            cx.propagate();
19241            return;
19242        };
19243
19244        if self.buffer.read(cx).is_singleton() {
19245            cx.propagate();
19246            return;
19247        }
19248
19249        let mut new_selections_by_buffer = HashMap::default();
19250        match &jump_data {
19251            Some(JumpData::MultiBufferPoint {
19252                excerpt_id,
19253                position,
19254                anchor,
19255                line_offset_from_top,
19256            }) => {
19257                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19258                if let Some(buffer) = multi_buffer_snapshot
19259                    .buffer_id_for_excerpt(*excerpt_id)
19260                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19261                {
19262                    let buffer_snapshot = buffer.read(cx).snapshot();
19263                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19264                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19265                    } else {
19266                        buffer_snapshot.clip_point(*position, Bias::Left)
19267                    };
19268                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19269                    new_selections_by_buffer.insert(
19270                        buffer,
19271                        (
19272                            vec![jump_to_offset..jump_to_offset],
19273                            Some(*line_offset_from_top),
19274                        ),
19275                    );
19276                }
19277            }
19278            Some(JumpData::MultiBufferRow {
19279                row,
19280                line_offset_from_top,
19281            }) => {
19282                let point = MultiBufferPoint::new(row.0, 0);
19283                if let Some((buffer, buffer_point, _)) =
19284                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19285                {
19286                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19287                    new_selections_by_buffer
19288                        .entry(buffer)
19289                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19290                        .0
19291                        .push(buffer_offset..buffer_offset)
19292                }
19293            }
19294            None => {
19295                let selections = self.selections.all::<usize>(cx);
19296                let multi_buffer = self.buffer.read(cx);
19297                for selection in selections {
19298                    for (snapshot, range, _, anchor) in multi_buffer
19299                        .snapshot(cx)
19300                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19301                    {
19302                        if let Some(anchor) = anchor {
19303                            // selection is in a deleted hunk
19304                            let Some(buffer_id) = anchor.buffer_id else {
19305                                continue;
19306                            };
19307                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19308                                continue;
19309                            };
19310                            let offset = text::ToOffset::to_offset(
19311                                &anchor.text_anchor,
19312                                &buffer_handle.read(cx).snapshot(),
19313                            );
19314                            let range = offset..offset;
19315                            new_selections_by_buffer
19316                                .entry(buffer_handle)
19317                                .or_insert((Vec::new(), None))
19318                                .0
19319                                .push(range)
19320                        } else {
19321                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19322                            else {
19323                                continue;
19324                            };
19325                            new_selections_by_buffer
19326                                .entry(buffer_handle)
19327                                .or_insert((Vec::new(), None))
19328                                .0
19329                                .push(range)
19330                        }
19331                    }
19332                }
19333            }
19334        }
19335
19336        new_selections_by_buffer
19337            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19338
19339        if new_selections_by_buffer.is_empty() {
19340            return;
19341        }
19342
19343        // We defer the pane interaction because we ourselves are a workspace item
19344        // and activating a new item causes the pane to call a method on us reentrantly,
19345        // which panics if we're on the stack.
19346        window.defer(cx, move |window, cx| {
19347            workspace.update(cx, |workspace, cx| {
19348                let pane = if split {
19349                    workspace.adjacent_pane(window, cx)
19350                } else {
19351                    workspace.active_pane().clone()
19352                };
19353
19354                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19355                    let editor = buffer
19356                        .read(cx)
19357                        .file()
19358                        .is_none()
19359                        .then(|| {
19360                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19361                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19362                            // Instead, we try to activate the existing editor in the pane first.
19363                            let (editor, pane_item_index) =
19364                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19365                                    let editor = item.downcast::<Editor>()?;
19366                                    let singleton_buffer =
19367                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19368                                    if singleton_buffer == buffer {
19369                                        Some((editor, i))
19370                                    } else {
19371                                        None
19372                                    }
19373                                })?;
19374                            pane.update(cx, |pane, cx| {
19375                                pane.activate_item(pane_item_index, true, true, window, cx)
19376                            });
19377                            Some(editor)
19378                        })
19379                        .flatten()
19380                        .unwrap_or_else(|| {
19381                            workspace.open_project_item::<Self>(
19382                                pane.clone(),
19383                                buffer,
19384                                true,
19385                                true,
19386                                window,
19387                                cx,
19388                            )
19389                        });
19390
19391                    editor.update(cx, |editor, cx| {
19392                        let autoscroll = match scroll_offset {
19393                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19394                            None => Autoscroll::newest(),
19395                        };
19396                        let nav_history = editor.nav_history.take();
19397                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19398                            s.select_ranges(ranges);
19399                        });
19400                        editor.nav_history = nav_history;
19401                    });
19402                }
19403            })
19404        });
19405    }
19406
19407    // For now, don't allow opening excerpts in buffers that aren't backed by
19408    // regular project files.
19409    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19410        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19411    }
19412
19413    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19414        let snapshot = self.buffer.read(cx).read(cx);
19415        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19416        Some(
19417            ranges
19418                .iter()
19419                .map(move |range| {
19420                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19421                })
19422                .collect(),
19423        )
19424    }
19425
19426    fn selection_replacement_ranges(
19427        &self,
19428        range: Range<OffsetUtf16>,
19429        cx: &mut App,
19430    ) -> Vec<Range<OffsetUtf16>> {
19431        let selections = self.selections.all::<OffsetUtf16>(cx);
19432        let newest_selection = selections
19433            .iter()
19434            .max_by_key(|selection| selection.id)
19435            .unwrap();
19436        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19437        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19438        let snapshot = self.buffer.read(cx).read(cx);
19439        selections
19440            .into_iter()
19441            .map(|mut selection| {
19442                selection.start.0 =
19443                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19444                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19445                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19446                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19447            })
19448            .collect()
19449    }
19450
19451    fn report_editor_event(
19452        &self,
19453        event_type: &'static str,
19454        file_extension: Option<String>,
19455        cx: &App,
19456    ) {
19457        if cfg!(any(test, feature = "test-support")) {
19458            return;
19459        }
19460
19461        let Some(project) = &self.project else { return };
19462
19463        // If None, we are in a file without an extension
19464        let file = self
19465            .buffer
19466            .read(cx)
19467            .as_singleton()
19468            .and_then(|b| b.read(cx).file());
19469        let file_extension = file_extension.or(file
19470            .as_ref()
19471            .and_then(|file| Path::new(file.file_name(cx)).extension())
19472            .and_then(|e| e.to_str())
19473            .map(|a| a.to_string()));
19474
19475        let vim_mode = vim_enabled(cx);
19476
19477        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19478        let copilot_enabled = edit_predictions_provider
19479            == language::language_settings::EditPredictionProvider::Copilot;
19480        let copilot_enabled_for_language = self
19481            .buffer
19482            .read(cx)
19483            .language_settings(cx)
19484            .show_edit_predictions;
19485
19486        let project = project.read(cx);
19487        telemetry::event!(
19488            event_type,
19489            file_extension,
19490            vim_mode,
19491            copilot_enabled,
19492            copilot_enabled_for_language,
19493            edit_predictions_provider,
19494            is_via_ssh = project.is_via_ssh(),
19495        );
19496    }
19497
19498    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19499    /// with each line being an array of {text, highlight} objects.
19500    fn copy_highlight_json(
19501        &mut self,
19502        _: &CopyHighlightJson,
19503        window: &mut Window,
19504        cx: &mut Context<Self>,
19505    ) {
19506        #[derive(Serialize)]
19507        struct Chunk<'a> {
19508            text: String,
19509            highlight: Option<&'a str>,
19510        }
19511
19512        let snapshot = self.buffer.read(cx).snapshot(cx);
19513        let range = self
19514            .selected_text_range(false, window, cx)
19515            .and_then(|selection| {
19516                if selection.range.is_empty() {
19517                    None
19518                } else {
19519                    Some(selection.range)
19520                }
19521            })
19522            .unwrap_or_else(|| 0..snapshot.len());
19523
19524        let chunks = snapshot.chunks(range, true);
19525        let mut lines = Vec::new();
19526        let mut line: VecDeque<Chunk> = VecDeque::new();
19527
19528        let Some(style) = self.style.as_ref() else {
19529            return;
19530        };
19531
19532        for chunk in chunks {
19533            let highlight = chunk
19534                .syntax_highlight_id
19535                .and_then(|id| id.name(&style.syntax));
19536            let mut chunk_lines = chunk.text.split('\n').peekable();
19537            while let Some(text) = chunk_lines.next() {
19538                let mut merged_with_last_token = false;
19539                if let Some(last_token) = line.back_mut() {
19540                    if last_token.highlight == highlight {
19541                        last_token.text.push_str(text);
19542                        merged_with_last_token = true;
19543                    }
19544                }
19545
19546                if !merged_with_last_token {
19547                    line.push_back(Chunk {
19548                        text: text.into(),
19549                        highlight,
19550                    });
19551                }
19552
19553                if chunk_lines.peek().is_some() {
19554                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19555                        line.pop_front();
19556                    }
19557                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19558                        line.pop_back();
19559                    }
19560
19561                    lines.push(mem::take(&mut line));
19562                }
19563            }
19564        }
19565
19566        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19567            return;
19568        };
19569        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19570    }
19571
19572    pub fn open_context_menu(
19573        &mut self,
19574        _: &OpenContextMenu,
19575        window: &mut Window,
19576        cx: &mut Context<Self>,
19577    ) {
19578        self.request_autoscroll(Autoscroll::newest(), cx);
19579        let position = self.selections.newest_display(cx).start;
19580        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19581    }
19582
19583    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19584        &self.inlay_hint_cache
19585    }
19586
19587    pub fn replay_insert_event(
19588        &mut self,
19589        text: &str,
19590        relative_utf16_range: Option<Range<isize>>,
19591        window: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        if !self.input_enabled {
19595            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19596            return;
19597        }
19598        if let Some(relative_utf16_range) = relative_utf16_range {
19599            let selections = self.selections.all::<OffsetUtf16>(cx);
19600            self.change_selections(None, window, cx, |s| {
19601                let new_ranges = selections.into_iter().map(|range| {
19602                    let start = OffsetUtf16(
19603                        range
19604                            .head()
19605                            .0
19606                            .saturating_add_signed(relative_utf16_range.start),
19607                    );
19608                    let end = OffsetUtf16(
19609                        range
19610                            .head()
19611                            .0
19612                            .saturating_add_signed(relative_utf16_range.end),
19613                    );
19614                    start..end
19615                });
19616                s.select_ranges(new_ranges);
19617            });
19618        }
19619
19620        self.handle_input(text, window, cx);
19621    }
19622
19623    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19624        let Some(provider) = self.semantics_provider.as_ref() else {
19625            return false;
19626        };
19627
19628        let mut supports = false;
19629        self.buffer().update(cx, |this, cx| {
19630            this.for_each_buffer(|buffer| {
19631                supports |= provider.supports_inlay_hints(buffer, cx);
19632            });
19633        });
19634
19635        supports
19636    }
19637
19638    pub fn is_focused(&self, window: &Window) -> bool {
19639        self.focus_handle.is_focused(window)
19640    }
19641
19642    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19643        cx.emit(EditorEvent::Focused);
19644
19645        if let Some(descendant) = self
19646            .last_focused_descendant
19647            .take()
19648            .and_then(|descendant| descendant.upgrade())
19649        {
19650            window.focus(&descendant);
19651        } else {
19652            if let Some(blame) = self.blame.as_ref() {
19653                blame.update(cx, GitBlame::focus)
19654            }
19655
19656            self.blink_manager.update(cx, BlinkManager::enable);
19657            self.show_cursor_names(window, cx);
19658            self.buffer.update(cx, |buffer, cx| {
19659                buffer.finalize_last_transaction(cx);
19660                if self.leader_id.is_none() {
19661                    buffer.set_active_selections(
19662                        &self.selections.disjoint_anchors(),
19663                        self.selections.line_mode,
19664                        self.cursor_shape,
19665                        cx,
19666                    );
19667                }
19668            });
19669        }
19670    }
19671
19672    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19673        cx.emit(EditorEvent::FocusedIn)
19674    }
19675
19676    fn handle_focus_out(
19677        &mut self,
19678        event: FocusOutEvent,
19679        _window: &mut Window,
19680        cx: &mut Context<Self>,
19681    ) {
19682        if event.blurred != self.focus_handle {
19683            self.last_focused_descendant = Some(event.blurred);
19684        }
19685        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19686    }
19687
19688    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19689        self.blink_manager.update(cx, BlinkManager::disable);
19690        self.buffer
19691            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19692
19693        if let Some(blame) = self.blame.as_ref() {
19694            blame.update(cx, GitBlame::blur)
19695        }
19696        if !self.hover_state.focused(window, cx) {
19697            hide_hover(self, cx);
19698        }
19699        if !self
19700            .context_menu
19701            .borrow()
19702            .as_ref()
19703            .is_some_and(|context_menu| context_menu.focused(window, cx))
19704        {
19705            self.hide_context_menu(window, cx);
19706        }
19707        self.discard_inline_completion(false, cx);
19708        cx.emit(EditorEvent::Blurred);
19709        cx.notify();
19710    }
19711
19712    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19713        let mut pending: String = window
19714            .pending_input_keystrokes()
19715            .into_iter()
19716            .flatten()
19717            .filter_map(|keystroke| {
19718                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19719                    Some(keystroke.key_char.clone().unwrap_or(keystroke.key.clone()))
19720                } else {
19721                    None
19722                }
19723            })
19724            .collect();
19725
19726        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19727            pending = "".to_string();
19728        }
19729
19730        let existing_pending = self
19731            .text_highlights::<PendingInput>(cx)
19732            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19733        if existing_pending.is_none() && pending.is_empty() {
19734            return;
19735        }
19736        let transaction =
19737            self.transact(window, cx, |this, window, cx| {
19738                let selections = this.selections.all::<usize>(cx);
19739                let edits = selections
19740                    .iter()
19741                    .map(|selection| (selection.end..selection.end, pending.clone()));
19742                this.edit(edits, cx);
19743                this.change_selections(None, window, cx, |s| {
19744                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19745                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19746                    }));
19747                });
19748                if let Some(existing_ranges) = existing_pending {
19749                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19750                    this.edit(edits, cx);
19751                }
19752            });
19753
19754        let snapshot = self.snapshot(window, cx);
19755        let ranges = self
19756            .selections
19757            .all::<usize>(cx)
19758            .into_iter()
19759            .map(|selection| {
19760                snapshot.buffer_snapshot.anchor_after(selection.end)
19761                    ..snapshot
19762                        .buffer_snapshot
19763                        .anchor_before(selection.end + pending.len())
19764            })
19765            .collect();
19766
19767        if pending.is_empty() {
19768            self.clear_highlights::<PendingInput>(cx);
19769        } else {
19770            self.highlight_text::<PendingInput>(
19771                ranges,
19772                HighlightStyle {
19773                    underline: Some(UnderlineStyle {
19774                        thickness: px(1.),
19775                        color: None,
19776                        wavy: false,
19777                    }),
19778                    ..Default::default()
19779                },
19780                cx,
19781            );
19782        }
19783
19784        self.ime_transaction = self.ime_transaction.or(transaction);
19785        if let Some(transaction) = self.ime_transaction {
19786            self.buffer.update(cx, |buffer, cx| {
19787                buffer.group_until_transaction(transaction, cx);
19788            });
19789        }
19790
19791        if self.text_highlights::<PendingInput>(cx).is_none() {
19792            self.ime_transaction.take();
19793        }
19794    }
19795
19796    pub fn register_action<A: Action>(
19797        &mut self,
19798        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19799    ) -> Subscription {
19800        let id = self.next_editor_action_id.post_inc();
19801        let listener = Arc::new(listener);
19802        self.editor_actions.borrow_mut().insert(
19803            id,
19804            Box::new(move |window, _| {
19805                let listener = listener.clone();
19806                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19807                    let action = action.downcast_ref().unwrap();
19808                    if phase == DispatchPhase::Bubble {
19809                        listener(action, window, cx)
19810                    }
19811                })
19812            }),
19813        );
19814
19815        let editor_actions = self.editor_actions.clone();
19816        Subscription::new(move || {
19817            editor_actions.borrow_mut().remove(&id);
19818        })
19819    }
19820
19821    pub fn file_header_size(&self) -> u32 {
19822        FILE_HEADER_HEIGHT
19823    }
19824
19825    pub fn restore(
19826        &mut self,
19827        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19828        window: &mut Window,
19829        cx: &mut Context<Self>,
19830    ) {
19831        let workspace = self.workspace();
19832        let project = self.project.as_ref();
19833        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19834            let mut tasks = Vec::new();
19835            for (buffer_id, changes) in revert_changes {
19836                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19837                    buffer.update(cx, |buffer, cx| {
19838                        buffer.edit(
19839                            changes
19840                                .into_iter()
19841                                .map(|(range, text)| (range, text.to_string())),
19842                            None,
19843                            cx,
19844                        );
19845                    });
19846
19847                    if let Some(project) =
19848                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19849                    {
19850                        project.update(cx, |project, cx| {
19851                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19852                        })
19853                    }
19854                }
19855            }
19856            tasks
19857        });
19858        cx.spawn_in(window, async move |_, cx| {
19859            for (buffer, task) in save_tasks {
19860                let result = task.await;
19861                if result.is_err() {
19862                    let Some(path) = buffer
19863                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19864                        .ok()
19865                    else {
19866                        continue;
19867                    };
19868                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19869                        let Some(task) = cx
19870                            .update_window_entity(&workspace, |workspace, window, cx| {
19871                                workspace
19872                                    .open_path_preview(path, None, false, false, false, window, cx)
19873                            })
19874                            .ok()
19875                        else {
19876                            continue;
19877                        };
19878                        task.await.log_err();
19879                    }
19880                }
19881            }
19882        })
19883        .detach();
19884        self.change_selections(None, window, cx, |selections| selections.refresh());
19885    }
19886
19887    pub fn to_pixel_point(
19888        &self,
19889        source: multi_buffer::Anchor,
19890        editor_snapshot: &EditorSnapshot,
19891        window: &mut Window,
19892    ) -> Option<gpui::Point<Pixels>> {
19893        let source_point = source.to_display_point(editor_snapshot);
19894        self.display_to_pixel_point(source_point, editor_snapshot, window)
19895    }
19896
19897    pub fn display_to_pixel_point(
19898        &self,
19899        source: DisplayPoint,
19900        editor_snapshot: &EditorSnapshot,
19901        window: &mut Window,
19902    ) -> Option<gpui::Point<Pixels>> {
19903        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19904        let text_layout_details = self.text_layout_details(window);
19905        let scroll_top = text_layout_details
19906            .scroll_anchor
19907            .scroll_position(editor_snapshot)
19908            .y;
19909
19910        if source.row().as_f32() < scroll_top.floor() {
19911            return None;
19912        }
19913        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19914        let source_y = line_height * (source.row().as_f32() - scroll_top);
19915        Some(gpui::Point::new(source_x, source_y))
19916    }
19917
19918    pub fn has_visible_completions_menu(&self) -> bool {
19919        !self.edit_prediction_preview_is_active()
19920            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19921                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19922            })
19923    }
19924
19925    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19926        if self.mode.is_minimap() {
19927            return;
19928        }
19929        self.addons
19930            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19931    }
19932
19933    pub fn unregister_addon<T: Addon>(&mut self) {
19934        self.addons.remove(&std::any::TypeId::of::<T>());
19935    }
19936
19937    pub fn addon<T: Addon>(&self) -> Option<&T> {
19938        let type_id = std::any::TypeId::of::<T>();
19939        self.addons
19940            .get(&type_id)
19941            .and_then(|item| item.to_any().downcast_ref::<T>())
19942    }
19943
19944    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19945        let type_id = std::any::TypeId::of::<T>();
19946        self.addons
19947            .get_mut(&type_id)
19948            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19949    }
19950
19951    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19952        let text_layout_details = self.text_layout_details(window);
19953        let style = &text_layout_details.editor_style;
19954        let font_id = window.text_system().resolve_font(&style.text.font());
19955        let font_size = style.text.font_size.to_pixels(window.rem_size());
19956        let line_height = style.text.line_height_in_pixels(window.rem_size());
19957        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19958
19959        gpui::Size::new(em_width, line_height)
19960    }
19961
19962    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19963        self.load_diff_task.clone()
19964    }
19965
19966    fn read_metadata_from_db(
19967        &mut self,
19968        item_id: u64,
19969        workspace_id: WorkspaceId,
19970        window: &mut Window,
19971        cx: &mut Context<Editor>,
19972    ) {
19973        if self.is_singleton(cx)
19974            && !self.mode.is_minimap()
19975            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19976        {
19977            let buffer_snapshot = OnceCell::new();
19978
19979            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19980                if !folds.is_empty() {
19981                    let snapshot =
19982                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19983                    self.fold_ranges(
19984                        folds
19985                            .into_iter()
19986                            .map(|(start, end)| {
19987                                snapshot.clip_offset(start, Bias::Left)
19988                                    ..snapshot.clip_offset(end, Bias::Right)
19989                            })
19990                            .collect(),
19991                        false,
19992                        window,
19993                        cx,
19994                    );
19995                }
19996            }
19997
19998            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19999                if !selections.is_empty() {
20000                    let snapshot =
20001                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20002                    self.change_selections(None, window, cx, |s| {
20003                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20004                            snapshot.clip_offset(start, Bias::Left)
20005                                ..snapshot.clip_offset(end, Bias::Right)
20006                        }));
20007                    });
20008                }
20009            };
20010        }
20011
20012        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20013    }
20014}
20015
20016fn vim_enabled(cx: &App) -> bool {
20017    cx.global::<SettingsStore>()
20018        .raw_user_settings()
20019        .get("vim_mode")
20020        == Some(&serde_json::Value::Bool(true))
20021}
20022
20023fn process_completion_for_edit(
20024    completion: &Completion,
20025    intent: CompletionIntent,
20026    buffer: &Entity<Buffer>,
20027    cursor_position: &text::Anchor,
20028    cx: &mut Context<Editor>,
20029) -> CompletionEdit {
20030    let buffer = buffer.read(cx);
20031    let buffer_snapshot = buffer.snapshot();
20032    let (snippet, new_text) = if completion.is_snippet() {
20033        let mut snippet_source = completion.new_text.clone();
20034        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
20035            if scope.prefers_label_for_snippet_in_completion() {
20036                if let Some(label) = completion.label() {
20037                    if matches!(
20038                        completion.kind(),
20039                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20040                    ) {
20041                        snippet_source = label;
20042                    }
20043                }
20044            }
20045        }
20046        match Snippet::parse(&snippet_source).log_err() {
20047            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20048            None => (None, completion.new_text.clone()),
20049        }
20050    } else {
20051        (None, completion.new_text.clone())
20052    };
20053
20054    let mut range_to_replace = {
20055        let replace_range = &completion.replace_range;
20056        if let CompletionSource::Lsp {
20057            insert_range: Some(insert_range),
20058            ..
20059        } = &completion.source
20060        {
20061            debug_assert_eq!(
20062                insert_range.start, replace_range.start,
20063                "insert_range and replace_range should start at the same position"
20064            );
20065            debug_assert!(
20066                insert_range
20067                    .start
20068                    .cmp(&cursor_position, &buffer_snapshot)
20069                    .is_le(),
20070                "insert_range should start before or at cursor position"
20071            );
20072            debug_assert!(
20073                replace_range
20074                    .start
20075                    .cmp(&cursor_position, &buffer_snapshot)
20076                    .is_le(),
20077                "replace_range should start before or at cursor position"
20078            );
20079            debug_assert!(
20080                insert_range
20081                    .end
20082                    .cmp(&cursor_position, &buffer_snapshot)
20083                    .is_le(),
20084                "insert_range should end before or at cursor position"
20085            );
20086
20087            let should_replace = match intent {
20088                CompletionIntent::CompleteWithInsert => false,
20089                CompletionIntent::CompleteWithReplace => true,
20090                CompletionIntent::Complete | CompletionIntent::Compose => {
20091                    let insert_mode =
20092                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20093                            .completions
20094                            .lsp_insert_mode;
20095                    match insert_mode {
20096                        LspInsertMode::Insert => false,
20097                        LspInsertMode::Replace => true,
20098                        LspInsertMode::ReplaceSubsequence => {
20099                            let mut text_to_replace = buffer.chars_for_range(
20100                                buffer.anchor_before(replace_range.start)
20101                                    ..buffer.anchor_after(replace_range.end),
20102                            );
20103                            let mut current_needle = text_to_replace.next();
20104                            for haystack_ch in completion.label.text.chars() {
20105                                if let Some(needle_ch) = current_needle {
20106                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20107                                        current_needle = text_to_replace.next();
20108                                    }
20109                                }
20110                            }
20111                            current_needle.is_none()
20112                        }
20113                        LspInsertMode::ReplaceSuffix => {
20114                            if replace_range
20115                                .end
20116                                .cmp(&cursor_position, &buffer_snapshot)
20117                                .is_gt()
20118                            {
20119                                let range_after_cursor = *cursor_position..replace_range.end;
20120                                let text_after_cursor = buffer
20121                                    .text_for_range(
20122                                        buffer.anchor_before(range_after_cursor.start)
20123                                            ..buffer.anchor_after(range_after_cursor.end),
20124                                    )
20125                                    .collect::<String>()
20126                                    .to_ascii_lowercase();
20127                                completion
20128                                    .label
20129                                    .text
20130                                    .to_ascii_lowercase()
20131                                    .ends_with(&text_after_cursor)
20132                            } else {
20133                                true
20134                            }
20135                        }
20136                    }
20137                }
20138            };
20139
20140            if should_replace {
20141                replace_range.clone()
20142            } else {
20143                insert_range.clone()
20144            }
20145        } else {
20146            replace_range.clone()
20147        }
20148    };
20149
20150    if range_to_replace
20151        .end
20152        .cmp(&cursor_position, &buffer_snapshot)
20153        .is_lt()
20154    {
20155        range_to_replace.end = *cursor_position;
20156    }
20157
20158    CompletionEdit {
20159        new_text,
20160        replace_range: range_to_replace.to_offset(&buffer),
20161        snippet,
20162    }
20163}
20164
20165struct CompletionEdit {
20166    new_text: String,
20167    replace_range: Range<usize>,
20168    snippet: Option<Snippet>,
20169}
20170
20171fn insert_extra_newline_brackets(
20172    buffer: &MultiBufferSnapshot,
20173    range: Range<usize>,
20174    language: &language::LanguageScope,
20175) -> bool {
20176    let leading_whitespace_len = buffer
20177        .reversed_chars_at(range.start)
20178        .take_while(|c| c.is_whitespace() && *c != '\n')
20179        .map(|c| c.len_utf8())
20180        .sum::<usize>();
20181    let trailing_whitespace_len = buffer
20182        .chars_at(range.end)
20183        .take_while(|c| c.is_whitespace() && *c != '\n')
20184        .map(|c| c.len_utf8())
20185        .sum::<usize>();
20186    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20187
20188    language.brackets().any(|(pair, enabled)| {
20189        let pair_start = pair.start.trim_end();
20190        let pair_end = pair.end.trim_start();
20191
20192        enabled
20193            && pair.newline
20194            && buffer.contains_str_at(range.end, pair_end)
20195            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20196    })
20197}
20198
20199fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20200    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20201        [(buffer, range, _)] => (*buffer, range.clone()),
20202        _ => return false,
20203    };
20204    let pair = {
20205        let mut result: Option<BracketMatch> = None;
20206
20207        for pair in buffer
20208            .all_bracket_ranges(range.clone())
20209            .filter(move |pair| {
20210                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20211            })
20212        {
20213            let len = pair.close_range.end - pair.open_range.start;
20214
20215            if let Some(existing) = &result {
20216                let existing_len = existing.close_range.end - existing.open_range.start;
20217                if len > existing_len {
20218                    continue;
20219                }
20220            }
20221
20222            result = Some(pair);
20223        }
20224
20225        result
20226    };
20227    let Some(pair) = pair else {
20228        return false;
20229    };
20230    pair.newline_only
20231        && buffer
20232            .chars_for_range(pair.open_range.end..range.start)
20233            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20234            .all(|c| c.is_whitespace() && c != '\n')
20235}
20236
20237fn update_uncommitted_diff_for_buffer(
20238    editor: Entity<Editor>,
20239    project: &Entity<Project>,
20240    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20241    buffer: Entity<MultiBuffer>,
20242    cx: &mut App,
20243) -> Task<()> {
20244    let mut tasks = Vec::new();
20245    project.update(cx, |project, cx| {
20246        for buffer in buffers {
20247            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20248                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20249            }
20250        }
20251    });
20252    cx.spawn(async move |cx| {
20253        let diffs = future::join_all(tasks).await;
20254        if editor
20255            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20256            .unwrap_or(false)
20257        {
20258            return;
20259        }
20260
20261        buffer
20262            .update(cx, |buffer, cx| {
20263                for diff in diffs.into_iter().flatten() {
20264                    buffer.add_diff(diff, cx);
20265                }
20266            })
20267            .ok();
20268    })
20269}
20270
20271fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20272    let tab_size = tab_size.get() as usize;
20273    let mut width = offset;
20274
20275    for ch in text.chars() {
20276        width += if ch == '\t' {
20277            tab_size - (width % tab_size)
20278        } else {
20279            1
20280        };
20281    }
20282
20283    width - offset
20284}
20285
20286#[cfg(test)]
20287mod tests {
20288    use super::*;
20289
20290    #[test]
20291    fn test_string_size_with_expanded_tabs() {
20292        let nz = |val| NonZeroU32::new(val).unwrap();
20293        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20294        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20295        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20296        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20297        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20298        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20299        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20300        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20301    }
20302}
20303
20304/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20305struct WordBreakingTokenizer<'a> {
20306    input: &'a str,
20307}
20308
20309impl<'a> WordBreakingTokenizer<'a> {
20310    fn new(input: &'a str) -> Self {
20311        Self { input }
20312    }
20313}
20314
20315fn is_char_ideographic(ch: char) -> bool {
20316    use unicode_script::Script::*;
20317    use unicode_script::UnicodeScript;
20318    matches!(ch.script(), Han | Tangut | Yi)
20319}
20320
20321fn is_grapheme_ideographic(text: &str) -> bool {
20322    text.chars().any(is_char_ideographic)
20323}
20324
20325fn is_grapheme_whitespace(text: &str) -> bool {
20326    text.chars().any(|x| x.is_whitespace())
20327}
20328
20329fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20330    text.chars().next().map_or(false, |ch| {
20331        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20332    })
20333}
20334
20335#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20336enum WordBreakToken<'a> {
20337    Word { token: &'a str, grapheme_len: usize },
20338    InlineWhitespace { token: &'a str, grapheme_len: usize },
20339    Newline,
20340}
20341
20342impl<'a> Iterator for WordBreakingTokenizer<'a> {
20343    /// Yields a span, the count of graphemes in the token, and whether it was
20344    /// whitespace. Note that it also breaks at word boundaries.
20345    type Item = WordBreakToken<'a>;
20346
20347    fn next(&mut self) -> Option<Self::Item> {
20348        use unicode_segmentation::UnicodeSegmentation;
20349        if self.input.is_empty() {
20350            return None;
20351        }
20352
20353        let mut iter = self.input.graphemes(true).peekable();
20354        let mut offset = 0;
20355        let mut grapheme_len = 0;
20356        if let Some(first_grapheme) = iter.next() {
20357            let is_newline = first_grapheme == "\n";
20358            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20359            offset += first_grapheme.len();
20360            grapheme_len += 1;
20361            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20362                if let Some(grapheme) = iter.peek().copied() {
20363                    if should_stay_with_preceding_ideograph(grapheme) {
20364                        offset += grapheme.len();
20365                        grapheme_len += 1;
20366                    }
20367                }
20368            } else {
20369                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20370                let mut next_word_bound = words.peek().copied();
20371                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20372                    next_word_bound = words.next();
20373                }
20374                while let Some(grapheme) = iter.peek().copied() {
20375                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20376                        break;
20377                    };
20378                    if is_grapheme_whitespace(grapheme) != is_whitespace
20379                        || (grapheme == "\n") != is_newline
20380                    {
20381                        break;
20382                    };
20383                    offset += grapheme.len();
20384                    grapheme_len += 1;
20385                    iter.next();
20386                }
20387            }
20388            let token = &self.input[..offset];
20389            self.input = &self.input[offset..];
20390            if token == "\n" {
20391                Some(WordBreakToken::Newline)
20392            } else if is_whitespace {
20393                Some(WordBreakToken::InlineWhitespace {
20394                    token,
20395                    grapheme_len,
20396                })
20397            } else {
20398                Some(WordBreakToken::Word {
20399                    token,
20400                    grapheme_len,
20401                })
20402            }
20403        } else {
20404            None
20405        }
20406    }
20407}
20408
20409#[test]
20410fn test_word_breaking_tokenizer() {
20411    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20412        ("", &[]),
20413        ("  ", &[whitespace("  ", 2)]),
20414        ("Ʒ", &[word("Ʒ", 1)]),
20415        ("Ǽ", &[word("Ǽ", 1)]),
20416        ("", &[word("", 1)]),
20417        ("⋑⋑", &[word("⋑⋑", 2)]),
20418        (
20419            "原理,进而",
20420            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20421        ),
20422        (
20423            "hello world",
20424            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20425        ),
20426        (
20427            "hello, world",
20428            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20429        ),
20430        (
20431            "  hello world",
20432            &[
20433                whitespace("  ", 2),
20434                word("hello", 5),
20435                whitespace(" ", 1),
20436                word("world", 5),
20437            ],
20438        ),
20439        (
20440            "这是什么 \n 钢笔",
20441            &[
20442                word("", 1),
20443                word("", 1),
20444                word("", 1),
20445                word("", 1),
20446                whitespace(" ", 1),
20447                newline(),
20448                whitespace(" ", 1),
20449                word("", 1),
20450                word("", 1),
20451            ],
20452        ),
20453        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20454    ];
20455
20456    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20457        WordBreakToken::Word {
20458            token,
20459            grapheme_len,
20460        }
20461    }
20462
20463    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20464        WordBreakToken::InlineWhitespace {
20465            token,
20466            grapheme_len,
20467        }
20468    }
20469
20470    fn newline() -> WordBreakToken<'static> {
20471        WordBreakToken::Newline
20472    }
20473
20474    for (input, result) in tests {
20475        assert_eq!(
20476            WordBreakingTokenizer::new(input)
20477                .collect::<Vec<_>>()
20478                .as_slice(),
20479            *result,
20480        );
20481    }
20482}
20483
20484fn wrap_with_prefix(
20485    line_prefix: String,
20486    unwrapped_text: String,
20487    wrap_column: usize,
20488    tab_size: NonZeroU32,
20489    preserve_existing_whitespace: bool,
20490) -> String {
20491    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20492    let mut wrapped_text = String::new();
20493    let mut current_line = line_prefix.clone();
20494
20495    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20496    let mut current_line_len = line_prefix_len;
20497    let mut in_whitespace = false;
20498    for token in tokenizer {
20499        let have_preceding_whitespace = in_whitespace;
20500        match token {
20501            WordBreakToken::Word {
20502                token,
20503                grapheme_len,
20504            } => {
20505                in_whitespace = false;
20506                if current_line_len + grapheme_len > wrap_column
20507                    && current_line_len != line_prefix_len
20508                {
20509                    wrapped_text.push_str(current_line.trim_end());
20510                    wrapped_text.push('\n');
20511                    current_line.truncate(line_prefix.len());
20512                    current_line_len = line_prefix_len;
20513                }
20514                current_line.push_str(token);
20515                current_line_len += grapheme_len;
20516            }
20517            WordBreakToken::InlineWhitespace {
20518                mut token,
20519                mut grapheme_len,
20520            } => {
20521                in_whitespace = true;
20522                if have_preceding_whitespace && !preserve_existing_whitespace {
20523                    continue;
20524                }
20525                if !preserve_existing_whitespace {
20526                    token = " ";
20527                    grapheme_len = 1;
20528                }
20529                if current_line_len + grapheme_len > wrap_column {
20530                    wrapped_text.push_str(current_line.trim_end());
20531                    wrapped_text.push('\n');
20532                    current_line.truncate(line_prefix.len());
20533                    current_line_len = line_prefix_len;
20534                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20535                    current_line.push_str(token);
20536                    current_line_len += grapheme_len;
20537                }
20538            }
20539            WordBreakToken::Newline => {
20540                in_whitespace = true;
20541                if preserve_existing_whitespace {
20542                    wrapped_text.push_str(current_line.trim_end());
20543                    wrapped_text.push('\n');
20544                    current_line.truncate(line_prefix.len());
20545                    current_line_len = line_prefix_len;
20546                } else if have_preceding_whitespace {
20547                    continue;
20548                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20549                {
20550                    wrapped_text.push_str(current_line.trim_end());
20551                    wrapped_text.push('\n');
20552                    current_line.truncate(line_prefix.len());
20553                    current_line_len = line_prefix_len;
20554                } else if current_line_len != line_prefix_len {
20555                    current_line.push(' ');
20556                    current_line_len += 1;
20557                }
20558            }
20559        }
20560    }
20561
20562    if !current_line.is_empty() {
20563        wrapped_text.push_str(&current_line);
20564    }
20565    wrapped_text
20566}
20567
20568#[test]
20569fn test_wrap_with_prefix() {
20570    assert_eq!(
20571        wrap_with_prefix(
20572            "# ".to_string(),
20573            "abcdefg".to_string(),
20574            4,
20575            NonZeroU32::new(4).unwrap(),
20576            false,
20577        ),
20578        "# abcdefg"
20579    );
20580    assert_eq!(
20581        wrap_with_prefix(
20582            "".to_string(),
20583            "\thello world".to_string(),
20584            8,
20585            NonZeroU32::new(4).unwrap(),
20586            false,
20587        ),
20588        "hello\nworld"
20589    );
20590    assert_eq!(
20591        wrap_with_prefix(
20592            "// ".to_string(),
20593            "xx \nyy zz aa bb cc".to_string(),
20594            12,
20595            NonZeroU32::new(4).unwrap(),
20596            false,
20597        ),
20598        "// xx yy zz\n// aa bb cc"
20599    );
20600    assert_eq!(
20601        wrap_with_prefix(
20602            String::new(),
20603            "这是什么 \n 钢笔".to_string(),
20604            3,
20605            NonZeroU32::new(4).unwrap(),
20606            false,
20607        ),
20608        "这是什\n么 钢\n"
20609    );
20610}
20611
20612pub trait CollaborationHub {
20613    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20614    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20615    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20616}
20617
20618impl CollaborationHub for Entity<Project> {
20619    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20620        self.read(cx).collaborators()
20621    }
20622
20623    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20624        self.read(cx).user_store().read(cx).participant_indices()
20625    }
20626
20627    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20628        let this = self.read(cx);
20629        let user_ids = this.collaborators().values().map(|c| c.user_id);
20630        this.user_store().read(cx).participant_names(user_ids, cx)
20631    }
20632}
20633
20634pub trait SemanticsProvider {
20635    fn hover(
20636        &self,
20637        buffer: &Entity<Buffer>,
20638        position: text::Anchor,
20639        cx: &mut App,
20640    ) -> Option<Task<Vec<project::Hover>>>;
20641
20642    fn inline_values(
20643        &self,
20644        buffer_handle: Entity<Buffer>,
20645        range: Range<text::Anchor>,
20646        cx: &mut App,
20647    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20648
20649    fn inlay_hints(
20650        &self,
20651        buffer_handle: Entity<Buffer>,
20652        range: Range<text::Anchor>,
20653        cx: &mut App,
20654    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20655
20656    fn resolve_inlay_hint(
20657        &self,
20658        hint: InlayHint,
20659        buffer_handle: Entity<Buffer>,
20660        server_id: LanguageServerId,
20661        cx: &mut App,
20662    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20663
20664    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20665
20666    fn document_highlights(
20667        &self,
20668        buffer: &Entity<Buffer>,
20669        position: text::Anchor,
20670        cx: &mut App,
20671    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20672
20673    fn definitions(
20674        &self,
20675        buffer: &Entity<Buffer>,
20676        position: text::Anchor,
20677        kind: GotoDefinitionKind,
20678        cx: &mut App,
20679    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20680
20681    fn range_for_rename(
20682        &self,
20683        buffer: &Entity<Buffer>,
20684        position: text::Anchor,
20685        cx: &mut App,
20686    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20687
20688    fn perform_rename(
20689        &self,
20690        buffer: &Entity<Buffer>,
20691        position: text::Anchor,
20692        new_name: String,
20693        cx: &mut App,
20694    ) -> Option<Task<Result<ProjectTransaction>>>;
20695
20696    fn pull_diagnostics_for_buffer(
20697        &self,
20698        buffer: Entity<Buffer>,
20699        cx: &mut App,
20700    ) -> Task<anyhow::Result<()>>;
20701}
20702
20703pub trait CompletionProvider {
20704    fn completions(
20705        &self,
20706        excerpt_id: ExcerptId,
20707        buffer: &Entity<Buffer>,
20708        buffer_position: text::Anchor,
20709        trigger: CompletionContext,
20710        window: &mut Window,
20711        cx: &mut Context<Editor>,
20712    ) -> Task<Result<Vec<CompletionResponse>>>;
20713
20714    fn resolve_completions(
20715        &self,
20716        _buffer: Entity<Buffer>,
20717        _completion_indices: Vec<usize>,
20718        _completions: Rc<RefCell<Box<[Completion]>>>,
20719        _cx: &mut Context<Editor>,
20720    ) -> Task<Result<bool>> {
20721        Task::ready(Ok(false))
20722    }
20723
20724    fn apply_additional_edits_for_completion(
20725        &self,
20726        _buffer: Entity<Buffer>,
20727        _completions: Rc<RefCell<Box<[Completion]>>>,
20728        _completion_index: usize,
20729        _push_to_history: bool,
20730        _cx: &mut Context<Editor>,
20731    ) -> Task<Result<Option<language::Transaction>>> {
20732        Task::ready(Ok(None))
20733    }
20734
20735    fn is_completion_trigger(
20736        &self,
20737        buffer: &Entity<Buffer>,
20738        position: language::Anchor,
20739        text: &str,
20740        trigger_in_words: bool,
20741        menu_is_open: bool,
20742        cx: &mut Context<Editor>,
20743    ) -> bool;
20744
20745    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20746
20747    fn sort_completions(&self) -> bool {
20748        true
20749    }
20750
20751    fn filter_completions(&self) -> bool {
20752        true
20753    }
20754}
20755
20756pub trait CodeActionProvider {
20757    fn id(&self) -> Arc<str>;
20758
20759    fn code_actions(
20760        &self,
20761        buffer: &Entity<Buffer>,
20762        range: Range<text::Anchor>,
20763        window: &mut Window,
20764        cx: &mut App,
20765    ) -> Task<Result<Vec<CodeAction>>>;
20766
20767    fn apply_code_action(
20768        &self,
20769        buffer_handle: Entity<Buffer>,
20770        action: CodeAction,
20771        excerpt_id: ExcerptId,
20772        push_to_history: bool,
20773        window: &mut Window,
20774        cx: &mut App,
20775    ) -> Task<Result<ProjectTransaction>>;
20776}
20777
20778impl CodeActionProvider for Entity<Project> {
20779    fn id(&self) -> Arc<str> {
20780        "project".into()
20781    }
20782
20783    fn code_actions(
20784        &self,
20785        buffer: &Entity<Buffer>,
20786        range: Range<text::Anchor>,
20787        _window: &mut Window,
20788        cx: &mut App,
20789    ) -> Task<Result<Vec<CodeAction>>> {
20790        self.update(cx, |project, cx| {
20791            let code_lens = project.code_lens(buffer, range.clone(), cx);
20792            let code_actions = project.code_actions(buffer, range, None, cx);
20793            cx.background_spawn(async move {
20794                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20795                Ok(code_lens
20796                    .context("code lens fetch")?
20797                    .into_iter()
20798                    .chain(code_actions.context("code action fetch")?)
20799                    .collect())
20800            })
20801        })
20802    }
20803
20804    fn apply_code_action(
20805        &self,
20806        buffer_handle: Entity<Buffer>,
20807        action: CodeAction,
20808        _excerpt_id: ExcerptId,
20809        push_to_history: bool,
20810        _window: &mut Window,
20811        cx: &mut App,
20812    ) -> Task<Result<ProjectTransaction>> {
20813        self.update(cx, |project, cx| {
20814            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20815        })
20816    }
20817}
20818
20819fn snippet_completions(
20820    project: &Project,
20821    buffer: &Entity<Buffer>,
20822    buffer_position: text::Anchor,
20823    cx: &mut App,
20824) -> Task<Result<CompletionResponse>> {
20825    let languages = buffer.read(cx).languages_at(buffer_position);
20826    let snippet_store = project.snippets().read(cx);
20827
20828    let scopes: Vec<_> = languages
20829        .iter()
20830        .filter_map(|language| {
20831            let language_name = language.lsp_id();
20832            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20833
20834            if snippets.is_empty() {
20835                None
20836            } else {
20837                Some((language.default_scope(), snippets))
20838            }
20839        })
20840        .collect();
20841
20842    if scopes.is_empty() {
20843        return Task::ready(Ok(CompletionResponse {
20844            completions: vec![],
20845            is_incomplete: false,
20846        }));
20847    }
20848
20849    let snapshot = buffer.read(cx).text_snapshot();
20850    let chars: String = snapshot
20851        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20852        .collect();
20853    let executor = cx.background_executor().clone();
20854
20855    cx.background_spawn(async move {
20856        let mut is_incomplete = false;
20857        let mut completions: Vec<Completion> = Vec::new();
20858        for (scope, snippets) in scopes.into_iter() {
20859            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20860            let mut last_word = chars
20861                .chars()
20862                .take_while(|c| classifier.is_word(*c))
20863                .collect::<String>();
20864            last_word = last_word.chars().rev().collect();
20865
20866            if last_word.is_empty() {
20867                return Ok(CompletionResponse {
20868                    completions: vec![],
20869                    is_incomplete: true,
20870                });
20871            }
20872
20873            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20874            let to_lsp = |point: &text::Anchor| {
20875                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20876                point_to_lsp(end)
20877            };
20878            let lsp_end = to_lsp(&buffer_position);
20879
20880            let candidates = snippets
20881                .iter()
20882                .enumerate()
20883                .flat_map(|(ix, snippet)| {
20884                    snippet
20885                        .prefix
20886                        .iter()
20887                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20888                })
20889                .collect::<Vec<StringMatchCandidate>>();
20890
20891            const MAX_RESULTS: usize = 100;
20892            let mut matches = fuzzy::match_strings(
20893                &candidates,
20894                &last_word,
20895                last_word.chars().any(|c| c.is_uppercase()),
20896                MAX_RESULTS,
20897                &Default::default(),
20898                executor.clone(),
20899            )
20900            .await;
20901
20902            if matches.len() >= MAX_RESULTS {
20903                is_incomplete = true;
20904            }
20905
20906            // Remove all candidates where the query's start does not match the start of any word in the candidate
20907            if let Some(query_start) = last_word.chars().next() {
20908                matches.retain(|string_match| {
20909                    split_words(&string_match.string).any(|word| {
20910                        // Check that the first codepoint of the word as lowercase matches the first
20911                        // codepoint of the query as lowercase
20912                        word.chars()
20913                            .flat_map(|codepoint| codepoint.to_lowercase())
20914                            .zip(query_start.to_lowercase())
20915                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20916                    })
20917                });
20918            }
20919
20920            let matched_strings = matches
20921                .into_iter()
20922                .map(|m| m.string)
20923                .collect::<HashSet<_>>();
20924
20925            completions.extend(snippets.iter().filter_map(|snippet| {
20926                let matching_prefix = snippet
20927                    .prefix
20928                    .iter()
20929                    .find(|prefix| matched_strings.contains(*prefix))?;
20930                let start = as_offset - last_word.len();
20931                let start = snapshot.anchor_before(start);
20932                let range = start..buffer_position;
20933                let lsp_start = to_lsp(&start);
20934                let lsp_range = lsp::Range {
20935                    start: lsp_start,
20936                    end: lsp_end,
20937                };
20938                Some(Completion {
20939                    replace_range: range,
20940                    new_text: snippet.body.clone(),
20941                    source: CompletionSource::Lsp {
20942                        insert_range: None,
20943                        server_id: LanguageServerId(usize::MAX),
20944                        resolved: true,
20945                        lsp_completion: Box::new(lsp::CompletionItem {
20946                            label: snippet.prefix.first().unwrap().clone(),
20947                            kind: Some(CompletionItemKind::SNIPPET),
20948                            label_details: snippet.description.as_ref().map(|description| {
20949                                lsp::CompletionItemLabelDetails {
20950                                    detail: Some(description.clone()),
20951                                    description: None,
20952                                }
20953                            }),
20954                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20955                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20956                                lsp::InsertReplaceEdit {
20957                                    new_text: snippet.body.clone(),
20958                                    insert: lsp_range,
20959                                    replace: lsp_range,
20960                                },
20961                            )),
20962                            filter_text: Some(snippet.body.clone()),
20963                            sort_text: Some(char::MAX.to_string()),
20964                            ..lsp::CompletionItem::default()
20965                        }),
20966                        lsp_defaults: None,
20967                    },
20968                    label: CodeLabel {
20969                        text: matching_prefix.clone(),
20970                        runs: Vec::new(),
20971                        filter_range: 0..matching_prefix.len(),
20972                    },
20973                    icon_path: None,
20974                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20975                        single_line: snippet.name.clone().into(),
20976                        plain_text: snippet
20977                            .description
20978                            .clone()
20979                            .map(|description| description.into()),
20980                    }),
20981                    insert_text_mode: None,
20982                    confirm: None,
20983                })
20984            }))
20985        }
20986
20987        Ok(CompletionResponse {
20988            completions,
20989            is_incomplete,
20990        })
20991    })
20992}
20993
20994impl CompletionProvider for Entity<Project> {
20995    fn completions(
20996        &self,
20997        _excerpt_id: ExcerptId,
20998        buffer: &Entity<Buffer>,
20999        buffer_position: text::Anchor,
21000        options: CompletionContext,
21001        _window: &mut Window,
21002        cx: &mut Context<Editor>,
21003    ) -> Task<Result<Vec<CompletionResponse>>> {
21004        self.update(cx, |project, cx| {
21005            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21006            let project_completions = project.completions(buffer, buffer_position, options, cx);
21007            cx.background_spawn(async move {
21008                let mut responses = project_completions.await?;
21009                let snippets = snippets.await?;
21010                if !snippets.completions.is_empty() {
21011                    responses.push(snippets);
21012                }
21013                Ok(responses)
21014            })
21015        })
21016    }
21017
21018    fn resolve_completions(
21019        &self,
21020        buffer: Entity<Buffer>,
21021        completion_indices: Vec<usize>,
21022        completions: Rc<RefCell<Box<[Completion]>>>,
21023        cx: &mut Context<Editor>,
21024    ) -> Task<Result<bool>> {
21025        self.update(cx, |project, cx| {
21026            project.lsp_store().update(cx, |lsp_store, cx| {
21027                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21028            })
21029        })
21030    }
21031
21032    fn apply_additional_edits_for_completion(
21033        &self,
21034        buffer: Entity<Buffer>,
21035        completions: Rc<RefCell<Box<[Completion]>>>,
21036        completion_index: usize,
21037        push_to_history: bool,
21038        cx: &mut Context<Editor>,
21039    ) -> Task<Result<Option<language::Transaction>>> {
21040        self.update(cx, |project, cx| {
21041            project.lsp_store().update(cx, |lsp_store, cx| {
21042                lsp_store.apply_additional_edits_for_completion(
21043                    buffer,
21044                    completions,
21045                    completion_index,
21046                    push_to_history,
21047                    cx,
21048                )
21049            })
21050        })
21051    }
21052
21053    fn is_completion_trigger(
21054        &self,
21055        buffer: &Entity<Buffer>,
21056        position: language::Anchor,
21057        text: &str,
21058        trigger_in_words: bool,
21059        menu_is_open: bool,
21060        cx: &mut Context<Editor>,
21061    ) -> bool {
21062        let mut chars = text.chars();
21063        let char = if let Some(char) = chars.next() {
21064            char
21065        } else {
21066            return false;
21067        };
21068        if chars.next().is_some() {
21069            return false;
21070        }
21071
21072        let buffer = buffer.read(cx);
21073        let snapshot = buffer.snapshot();
21074        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21075            return false;
21076        }
21077        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21078        if trigger_in_words && classifier.is_word(char) {
21079            return true;
21080        }
21081
21082        buffer.completion_triggers().contains(text)
21083    }
21084}
21085
21086impl SemanticsProvider for Entity<Project> {
21087    fn hover(
21088        &self,
21089        buffer: &Entity<Buffer>,
21090        position: text::Anchor,
21091        cx: &mut App,
21092    ) -> Option<Task<Vec<project::Hover>>> {
21093        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21094    }
21095
21096    fn document_highlights(
21097        &self,
21098        buffer: &Entity<Buffer>,
21099        position: text::Anchor,
21100        cx: &mut App,
21101    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21102        Some(self.update(cx, |project, cx| {
21103            project.document_highlights(buffer, position, cx)
21104        }))
21105    }
21106
21107    fn definitions(
21108        &self,
21109        buffer: &Entity<Buffer>,
21110        position: text::Anchor,
21111        kind: GotoDefinitionKind,
21112        cx: &mut App,
21113    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21114        Some(self.update(cx, |project, cx| match kind {
21115            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21116            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21117            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21118            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21119        }))
21120    }
21121
21122    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21123        // TODO: make this work for remote projects
21124        self.update(cx, |project, cx| {
21125            if project
21126                .active_debug_session(cx)
21127                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21128            {
21129                return true;
21130            }
21131
21132            buffer.update(cx, |buffer, cx| {
21133                project.any_language_server_supports_inlay_hints(buffer, cx)
21134            })
21135        })
21136    }
21137
21138    fn inline_values(
21139        &self,
21140        buffer_handle: Entity<Buffer>,
21141
21142        range: Range<text::Anchor>,
21143        cx: &mut App,
21144    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21145        self.update(cx, |project, cx| {
21146            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21147
21148            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21149        })
21150    }
21151
21152    fn inlay_hints(
21153        &self,
21154        buffer_handle: Entity<Buffer>,
21155        range: Range<text::Anchor>,
21156        cx: &mut App,
21157    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21158        Some(self.update(cx, |project, cx| {
21159            project.inlay_hints(buffer_handle, range, cx)
21160        }))
21161    }
21162
21163    fn resolve_inlay_hint(
21164        &self,
21165        hint: InlayHint,
21166        buffer_handle: Entity<Buffer>,
21167        server_id: LanguageServerId,
21168        cx: &mut App,
21169    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21170        Some(self.update(cx, |project, cx| {
21171            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21172        }))
21173    }
21174
21175    fn range_for_rename(
21176        &self,
21177        buffer: &Entity<Buffer>,
21178        position: text::Anchor,
21179        cx: &mut App,
21180    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21181        Some(self.update(cx, |project, cx| {
21182            let buffer = buffer.clone();
21183            let task = project.prepare_rename(buffer.clone(), position, cx);
21184            cx.spawn(async move |_, cx| {
21185                Ok(match task.await? {
21186                    PrepareRenameResponse::Success(range) => Some(range),
21187                    PrepareRenameResponse::InvalidPosition => None,
21188                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21189                        // Fallback on using TreeSitter info to determine identifier range
21190                        buffer.read_with(cx, |buffer, _| {
21191                            let snapshot = buffer.snapshot();
21192                            let (range, kind) = snapshot.surrounding_word(position);
21193                            if kind != Some(CharKind::Word) {
21194                                return None;
21195                            }
21196                            Some(
21197                                snapshot.anchor_before(range.start)
21198                                    ..snapshot.anchor_after(range.end),
21199                            )
21200                        })?
21201                    }
21202                })
21203            })
21204        }))
21205    }
21206
21207    fn perform_rename(
21208        &self,
21209        buffer: &Entity<Buffer>,
21210        position: text::Anchor,
21211        new_name: String,
21212        cx: &mut App,
21213    ) -> Option<Task<Result<ProjectTransaction>>> {
21214        Some(self.update(cx, |project, cx| {
21215            project.perform_rename(buffer.clone(), position, new_name, cx)
21216        }))
21217    }
21218
21219    fn pull_diagnostics_for_buffer(
21220        &self,
21221        buffer: Entity<Buffer>,
21222        cx: &mut App,
21223    ) -> Task<anyhow::Result<()>> {
21224        let diagnostics = self.update(cx, |project, cx| {
21225            project
21226                .lsp_store()
21227                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21228        });
21229        let project = self.clone();
21230        cx.spawn(async move |cx| {
21231            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21232            project.update(cx, |project, cx| {
21233                project.lsp_store().update(cx, |lsp_store, cx| {
21234                    for diagnostics_set in diagnostics {
21235                        let LspPullDiagnostics::Response {
21236                            server_id,
21237                            uri,
21238                            diagnostics,
21239                        } = diagnostics_set
21240                        else {
21241                            continue;
21242                        };
21243
21244                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21245                        let disk_based_sources = adapter
21246                            .as_ref()
21247                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21248                            .unwrap_or(&[]);
21249                        match diagnostics {
21250                            PulledDiagnostics::Unchanged { result_id } => {
21251                                lsp_store
21252                                    .merge_diagnostics(
21253                                        server_id,
21254                                        lsp::PublishDiagnosticsParams {
21255                                            uri: uri.clone(),
21256                                            diagnostics: Vec::new(),
21257                                            version: None,
21258                                        },
21259                                        Some(result_id),
21260                                        DiagnosticSourceKind::Pulled,
21261                                        disk_based_sources,
21262                                        |_, _| true,
21263                                        cx,
21264                                    )
21265                                    .log_err();
21266                            }
21267                            PulledDiagnostics::Changed {
21268                                diagnostics,
21269                                result_id,
21270                            } => {
21271                                lsp_store
21272                                    .merge_diagnostics(
21273                                        server_id,
21274                                        lsp::PublishDiagnosticsParams {
21275                                            uri: uri.clone(),
21276                                            diagnostics,
21277                                            version: None,
21278                                        },
21279                                        result_id,
21280                                        DiagnosticSourceKind::Pulled,
21281                                        disk_based_sources,
21282                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21283                                            DiagnosticSourceKind::Pulled => false,
21284                                            DiagnosticSourceKind::Other
21285                                            | DiagnosticSourceKind::Pushed => true,
21286                                        },
21287                                        cx,
21288                                    )
21289                                    .log_err();
21290                            }
21291                        }
21292                    }
21293                })
21294            })
21295        })
21296    }
21297}
21298
21299fn inlay_hint_settings(
21300    location: Anchor,
21301    snapshot: &MultiBufferSnapshot,
21302    cx: &mut Context<Editor>,
21303) -> InlayHintSettings {
21304    let file = snapshot.file_at(location);
21305    let language = snapshot.language_at(location).map(|l| l.name());
21306    language_settings(language, file, cx).inlay_hints
21307}
21308
21309fn consume_contiguous_rows(
21310    contiguous_row_selections: &mut Vec<Selection<Point>>,
21311    selection: &Selection<Point>,
21312    display_map: &DisplaySnapshot,
21313    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21314) -> (MultiBufferRow, MultiBufferRow) {
21315    contiguous_row_selections.push(selection.clone());
21316    let start_row = MultiBufferRow(selection.start.row);
21317    let mut end_row = ending_row(selection, display_map);
21318
21319    while let Some(next_selection) = selections.peek() {
21320        if next_selection.start.row <= end_row.0 {
21321            end_row = ending_row(next_selection, display_map);
21322            contiguous_row_selections.push(selections.next().unwrap().clone());
21323        } else {
21324            break;
21325        }
21326    }
21327    (start_row, end_row)
21328}
21329
21330fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21331    if next_selection.end.column > 0 || next_selection.is_empty() {
21332        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21333    } else {
21334        MultiBufferRow(next_selection.end.row)
21335    }
21336}
21337
21338impl EditorSnapshot {
21339    pub fn remote_selections_in_range<'a>(
21340        &'a self,
21341        range: &'a Range<Anchor>,
21342        collaboration_hub: &dyn CollaborationHub,
21343        cx: &'a App,
21344    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21345        let participant_names = collaboration_hub.user_names(cx);
21346        let participant_indices = collaboration_hub.user_participant_indices(cx);
21347        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21348        let collaborators_by_replica_id = collaborators_by_peer_id
21349            .values()
21350            .map(|collaborator| (collaborator.replica_id, collaborator))
21351            .collect::<HashMap<_, _>>();
21352        self.buffer_snapshot
21353            .selections_in_range(range, false)
21354            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21355                if replica_id == AGENT_REPLICA_ID {
21356                    Some(RemoteSelection {
21357                        replica_id,
21358                        selection,
21359                        cursor_shape,
21360                        line_mode,
21361                        collaborator_id: CollaboratorId::Agent,
21362                        user_name: Some("Agent".into()),
21363                        color: cx.theme().players().agent(),
21364                    })
21365                } else {
21366                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21367                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21368                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21369                    Some(RemoteSelection {
21370                        replica_id,
21371                        selection,
21372                        cursor_shape,
21373                        line_mode,
21374                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21375                        user_name,
21376                        color: if let Some(index) = participant_index {
21377                            cx.theme().players().color_for_participant(index.0)
21378                        } else {
21379                            cx.theme().players().absent()
21380                        },
21381                    })
21382                }
21383            })
21384    }
21385
21386    pub fn hunks_for_ranges(
21387        &self,
21388        ranges: impl IntoIterator<Item = Range<Point>>,
21389    ) -> Vec<MultiBufferDiffHunk> {
21390        let mut hunks = Vec::new();
21391        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21392            HashMap::default();
21393        for query_range in ranges {
21394            let query_rows =
21395                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21396            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21397                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21398            ) {
21399                // Include deleted hunks that are adjacent to the query range, because
21400                // otherwise they would be missed.
21401                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21402                if hunk.status().is_deleted() {
21403                    intersects_range |= hunk.row_range.start == query_rows.end;
21404                    intersects_range |= hunk.row_range.end == query_rows.start;
21405                }
21406                if intersects_range {
21407                    if !processed_buffer_rows
21408                        .entry(hunk.buffer_id)
21409                        .or_default()
21410                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21411                    {
21412                        continue;
21413                    }
21414                    hunks.push(hunk);
21415                }
21416            }
21417        }
21418
21419        hunks
21420    }
21421
21422    fn display_diff_hunks_for_rows<'a>(
21423        &'a self,
21424        display_rows: Range<DisplayRow>,
21425        folded_buffers: &'a HashSet<BufferId>,
21426    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21427        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21428        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21429
21430        self.buffer_snapshot
21431            .diff_hunks_in_range(buffer_start..buffer_end)
21432            .filter_map(|hunk| {
21433                if folded_buffers.contains(&hunk.buffer_id) {
21434                    return None;
21435                }
21436
21437                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21438                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21439
21440                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21441                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21442
21443                let display_hunk = if hunk_display_start.column() != 0 {
21444                    DisplayDiffHunk::Folded {
21445                        display_row: hunk_display_start.row(),
21446                    }
21447                } else {
21448                    let mut end_row = hunk_display_end.row();
21449                    if hunk_display_end.column() > 0 {
21450                        end_row.0 += 1;
21451                    }
21452                    let is_created_file = hunk.is_created_file();
21453                    DisplayDiffHunk::Unfolded {
21454                        status: hunk.status(),
21455                        diff_base_byte_range: hunk.diff_base_byte_range,
21456                        display_row_range: hunk_display_start.row()..end_row,
21457                        multi_buffer_range: Anchor::range_in_buffer(
21458                            hunk.excerpt_id,
21459                            hunk.buffer_id,
21460                            hunk.buffer_range,
21461                        ),
21462                        is_created_file,
21463                    }
21464                };
21465
21466                Some(display_hunk)
21467            })
21468    }
21469
21470    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21471        self.display_snapshot.buffer_snapshot.language_at(position)
21472    }
21473
21474    pub fn is_focused(&self) -> bool {
21475        self.is_focused
21476    }
21477
21478    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21479        self.placeholder_text.as_ref()
21480    }
21481
21482    pub fn scroll_position(&self) -> gpui::Point<f32> {
21483        self.scroll_anchor.scroll_position(&self.display_snapshot)
21484    }
21485
21486    fn gutter_dimensions(
21487        &self,
21488        font_id: FontId,
21489        font_size: Pixels,
21490        max_line_number_width: Pixels,
21491        cx: &App,
21492    ) -> Option<GutterDimensions> {
21493        if !self.show_gutter {
21494            return None;
21495        }
21496
21497        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21498        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21499
21500        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21501            matches!(
21502                ProjectSettings::get_global(cx).git.git_gutter,
21503                Some(GitGutterSetting::TrackedFiles)
21504            )
21505        });
21506        let gutter_settings = EditorSettings::get_global(cx).gutter;
21507        let show_line_numbers = self
21508            .show_line_numbers
21509            .unwrap_or(gutter_settings.line_numbers);
21510        let line_gutter_width = if show_line_numbers {
21511            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21512            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21513            max_line_number_width.max(min_width_for_number_on_gutter)
21514        } else {
21515            0.0.into()
21516        };
21517
21518        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21519        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21520
21521        let git_blame_entries_width =
21522            self.git_blame_gutter_max_author_length
21523                .map(|max_author_length| {
21524                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21525                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21526
21527                    /// The number of characters to dedicate to gaps and margins.
21528                    const SPACING_WIDTH: usize = 4;
21529
21530                    let max_char_count = max_author_length.min(renderer.max_author_length())
21531                        + ::git::SHORT_SHA_LENGTH
21532                        + MAX_RELATIVE_TIMESTAMP.len()
21533                        + SPACING_WIDTH;
21534
21535                    em_advance * max_char_count
21536                });
21537
21538        let is_singleton = self.buffer_snapshot.is_singleton();
21539
21540        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21541        left_padding += if !is_singleton {
21542            em_width * 4.0
21543        } else if show_runnables || show_breakpoints {
21544            em_width * 3.0
21545        } else if show_git_gutter && show_line_numbers {
21546            em_width * 2.0
21547        } else if show_git_gutter || show_line_numbers {
21548            em_width
21549        } else {
21550            px(0.)
21551        };
21552
21553        let shows_folds = is_singleton && gutter_settings.folds;
21554
21555        let right_padding = if shows_folds && show_line_numbers {
21556            em_width * 4.0
21557        } else if shows_folds || (!is_singleton && show_line_numbers) {
21558            em_width * 3.0
21559        } else if show_line_numbers {
21560            em_width
21561        } else {
21562            px(0.)
21563        };
21564
21565        Some(GutterDimensions {
21566            left_padding,
21567            right_padding,
21568            width: line_gutter_width + left_padding + right_padding,
21569            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21570            git_blame_entries_width,
21571        })
21572    }
21573
21574    pub fn render_crease_toggle(
21575        &self,
21576        buffer_row: MultiBufferRow,
21577        row_contains_cursor: bool,
21578        editor: Entity<Editor>,
21579        window: &mut Window,
21580        cx: &mut App,
21581    ) -> Option<AnyElement> {
21582        let folded = self.is_line_folded(buffer_row);
21583        let mut is_foldable = false;
21584
21585        if let Some(crease) = self
21586            .crease_snapshot
21587            .query_row(buffer_row, &self.buffer_snapshot)
21588        {
21589            is_foldable = true;
21590            match crease {
21591                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21592                    if let Some(render_toggle) = render_toggle {
21593                        let toggle_callback =
21594                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21595                                if folded {
21596                                    editor.update(cx, |editor, cx| {
21597                                        editor.fold_at(buffer_row, window, cx)
21598                                    });
21599                                } else {
21600                                    editor.update(cx, |editor, cx| {
21601                                        editor.unfold_at(buffer_row, window, cx)
21602                                    });
21603                                }
21604                            });
21605                        return Some((render_toggle)(
21606                            buffer_row,
21607                            folded,
21608                            toggle_callback,
21609                            window,
21610                            cx,
21611                        ));
21612                    }
21613                }
21614            }
21615        }
21616
21617        is_foldable |= self.starts_indent(buffer_row);
21618
21619        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21620            Some(
21621                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21622                    .toggle_state(folded)
21623                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21624                        if folded {
21625                            this.unfold_at(buffer_row, window, cx);
21626                        } else {
21627                            this.fold_at(buffer_row, window, cx);
21628                        }
21629                    }))
21630                    .into_any_element(),
21631            )
21632        } else {
21633            None
21634        }
21635    }
21636
21637    pub fn render_crease_trailer(
21638        &self,
21639        buffer_row: MultiBufferRow,
21640        window: &mut Window,
21641        cx: &mut App,
21642    ) -> Option<AnyElement> {
21643        let folded = self.is_line_folded(buffer_row);
21644        if let Crease::Inline { render_trailer, .. } = self
21645            .crease_snapshot
21646            .query_row(buffer_row, &self.buffer_snapshot)?
21647        {
21648            let render_trailer = render_trailer.as_ref()?;
21649            Some(render_trailer(buffer_row, folded, window, cx))
21650        } else {
21651            None
21652        }
21653    }
21654}
21655
21656impl Deref for EditorSnapshot {
21657    type Target = DisplaySnapshot;
21658
21659    fn deref(&self) -> &Self::Target {
21660        &self.display_snapshot
21661    }
21662}
21663
21664#[derive(Clone, Debug, PartialEq, Eq)]
21665pub enum EditorEvent {
21666    InputIgnored {
21667        text: Arc<str>,
21668    },
21669    InputHandled {
21670        utf16_range_to_replace: Option<Range<isize>>,
21671        text: Arc<str>,
21672    },
21673    ExcerptsAdded {
21674        buffer: Entity<Buffer>,
21675        predecessor: ExcerptId,
21676        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21677    },
21678    ExcerptsRemoved {
21679        ids: Vec<ExcerptId>,
21680        removed_buffer_ids: Vec<BufferId>,
21681    },
21682    BufferFoldToggled {
21683        ids: Vec<ExcerptId>,
21684        folded: bool,
21685    },
21686    ExcerptsEdited {
21687        ids: Vec<ExcerptId>,
21688    },
21689    ExcerptsExpanded {
21690        ids: Vec<ExcerptId>,
21691    },
21692    BufferEdited,
21693    Edited {
21694        transaction_id: clock::Lamport,
21695    },
21696    Reparsed(BufferId),
21697    Focused,
21698    FocusedIn,
21699    Blurred,
21700    DirtyChanged,
21701    Saved,
21702    TitleChanged,
21703    DiffBaseChanged,
21704    SelectionsChanged {
21705        local: bool,
21706    },
21707    ScrollPositionChanged {
21708        local: bool,
21709        autoscroll: bool,
21710    },
21711    Closed,
21712    TransactionUndone {
21713        transaction_id: clock::Lamport,
21714    },
21715    TransactionBegun {
21716        transaction_id: clock::Lamport,
21717    },
21718    Reloaded,
21719    CursorShapeChanged,
21720    PushedToNavHistory {
21721        anchor: Anchor,
21722        is_deactivate: bool,
21723    },
21724}
21725
21726impl EventEmitter<EditorEvent> for Editor {}
21727
21728impl Focusable for Editor {
21729    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21730        self.focus_handle.clone()
21731    }
21732}
21733
21734impl Render for Editor {
21735    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21736        let settings = ThemeSettings::get_global(cx);
21737
21738        let mut text_style = match self.mode {
21739            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21740                color: cx.theme().colors().editor_foreground,
21741                font_family: settings.ui_font.family.clone(),
21742                font_features: settings.ui_font.features.clone(),
21743                font_fallbacks: settings.ui_font.fallbacks.clone(),
21744                font_size: rems(0.875).into(),
21745                font_weight: settings.ui_font.weight,
21746                line_height: relative(settings.buffer_line_height.value()),
21747                ..Default::default()
21748            },
21749            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21750                color: cx.theme().colors().editor_foreground,
21751                font_family: settings.buffer_font.family.clone(),
21752                font_features: settings.buffer_font.features.clone(),
21753                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21754                font_size: settings.buffer_font_size(cx).into(),
21755                font_weight: settings.buffer_font.weight,
21756                line_height: relative(settings.buffer_line_height.value()),
21757                ..Default::default()
21758            },
21759        };
21760        if let Some(text_style_refinement) = &self.text_style_refinement {
21761            text_style.refine(text_style_refinement)
21762        }
21763
21764        let background = match self.mode {
21765            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21766            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21767            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21768            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21769        };
21770
21771        EditorElement::new(
21772            &cx.entity(),
21773            EditorStyle {
21774                background,
21775                local_player: cx.theme().players().local(),
21776                text: text_style,
21777                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21778                syntax: cx.theme().syntax().clone(),
21779                status: cx.theme().status().clone(),
21780                inlay_hints_style: make_inlay_hints_style(cx),
21781                inline_completion_styles: make_suggestion_styles(cx),
21782                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21783                show_underlines: !self.mode.is_minimap(),
21784            },
21785        )
21786    }
21787}
21788
21789impl EntityInputHandler for Editor {
21790    fn text_for_range(
21791        &mut self,
21792        range_utf16: Range<usize>,
21793        adjusted_range: &mut Option<Range<usize>>,
21794        _: &mut Window,
21795        cx: &mut Context<Self>,
21796    ) -> Option<String> {
21797        let snapshot = self.buffer.read(cx).read(cx);
21798        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21799        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21800        if (start.0..end.0) != range_utf16 {
21801            adjusted_range.replace(start.0..end.0);
21802        }
21803        Some(snapshot.text_for_range(start..end).collect())
21804    }
21805
21806    fn selected_text_range(
21807        &mut self,
21808        ignore_disabled_input: bool,
21809        _: &mut Window,
21810        cx: &mut Context<Self>,
21811    ) -> Option<UTF16Selection> {
21812        // Prevent the IME menu from appearing when holding down an alphabetic key
21813        // while input is disabled.
21814        if !ignore_disabled_input && !self.input_enabled {
21815            return None;
21816        }
21817
21818        let selection = self.selections.newest::<OffsetUtf16>(cx);
21819        let range = selection.range();
21820
21821        Some(UTF16Selection {
21822            range: range.start.0..range.end.0,
21823            reversed: selection.reversed,
21824        })
21825    }
21826
21827    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21828        let snapshot = self.buffer.read(cx).read(cx);
21829        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21830        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21831    }
21832
21833    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21834        self.clear_highlights::<InputComposition>(cx);
21835        self.ime_transaction.take();
21836    }
21837
21838    fn replace_text_in_range(
21839        &mut self,
21840        range_utf16: Option<Range<usize>>,
21841        text: &str,
21842        window: &mut Window,
21843        cx: &mut Context<Self>,
21844    ) {
21845        if !self.input_enabled {
21846            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21847            return;
21848        }
21849
21850        self.transact(window, cx, |this, window, cx| {
21851            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21852                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21853                Some(this.selection_replacement_ranges(range_utf16, cx))
21854            } else {
21855                this.marked_text_ranges(cx)
21856            };
21857
21858            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21859                let newest_selection_id = this.selections.newest_anchor().id;
21860                this.selections
21861                    .all::<OffsetUtf16>(cx)
21862                    .iter()
21863                    .zip(ranges_to_replace.iter())
21864                    .find_map(|(selection, range)| {
21865                        if selection.id == newest_selection_id {
21866                            Some(
21867                                (range.start.0 as isize - selection.head().0 as isize)
21868                                    ..(range.end.0 as isize - selection.head().0 as isize),
21869                            )
21870                        } else {
21871                            None
21872                        }
21873                    })
21874            });
21875
21876            cx.emit(EditorEvent::InputHandled {
21877                utf16_range_to_replace: range_to_replace,
21878                text: text.into(),
21879            });
21880
21881            if let Some(new_selected_ranges) = new_selected_ranges {
21882                this.change_selections(None, window, cx, |selections| {
21883                    selections.select_ranges(new_selected_ranges)
21884                });
21885                this.backspace(&Default::default(), window, cx);
21886            }
21887
21888            this.handle_input(text, window, cx);
21889        });
21890
21891        if let Some(transaction) = self.ime_transaction {
21892            self.buffer.update(cx, |buffer, cx| {
21893                buffer.group_until_transaction(transaction, cx);
21894            });
21895        }
21896
21897        self.unmark_text(window, cx);
21898    }
21899
21900    fn replace_and_mark_text_in_range(
21901        &mut self,
21902        range_utf16: Option<Range<usize>>,
21903        text: &str,
21904        new_selected_range_utf16: Option<Range<usize>>,
21905        window: &mut Window,
21906        cx: &mut Context<Self>,
21907    ) {
21908        if !self.input_enabled {
21909            return;
21910        }
21911
21912        let transaction = self.transact(window, cx, |this, window, cx| {
21913            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21914                let snapshot = this.buffer.read(cx).read(cx);
21915                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21916                    for marked_range in &mut marked_ranges {
21917                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21918                        marked_range.start.0 += relative_range_utf16.start;
21919                        marked_range.start =
21920                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21921                        marked_range.end =
21922                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21923                    }
21924                }
21925                Some(marked_ranges)
21926            } else if let Some(range_utf16) = range_utf16 {
21927                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21928                Some(this.selection_replacement_ranges(range_utf16, cx))
21929            } else {
21930                None
21931            };
21932
21933            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21934                let newest_selection_id = this.selections.newest_anchor().id;
21935                this.selections
21936                    .all::<OffsetUtf16>(cx)
21937                    .iter()
21938                    .zip(ranges_to_replace.iter())
21939                    .find_map(|(selection, range)| {
21940                        if selection.id == newest_selection_id {
21941                            Some(
21942                                (range.start.0 as isize - selection.head().0 as isize)
21943                                    ..(range.end.0 as isize - selection.head().0 as isize),
21944                            )
21945                        } else {
21946                            None
21947                        }
21948                    })
21949            });
21950
21951            cx.emit(EditorEvent::InputHandled {
21952                utf16_range_to_replace: range_to_replace,
21953                text: text.into(),
21954            });
21955
21956            if let Some(ranges) = ranges_to_replace {
21957                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21958            }
21959
21960            let marked_ranges = {
21961                let snapshot = this.buffer.read(cx).read(cx);
21962                this.selections
21963                    .disjoint_anchors()
21964                    .iter()
21965                    .map(|selection| {
21966                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21967                    })
21968                    .collect::<Vec<_>>()
21969            };
21970
21971            if text.is_empty() {
21972                this.unmark_text(window, cx);
21973            } else {
21974                this.highlight_text::<InputComposition>(
21975                    marked_ranges.clone(),
21976                    HighlightStyle {
21977                        underline: Some(UnderlineStyle {
21978                            thickness: px(1.),
21979                            color: None,
21980                            wavy: false,
21981                        }),
21982                        ..Default::default()
21983                    },
21984                    cx,
21985                );
21986            }
21987
21988            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21989            let use_autoclose = this.use_autoclose;
21990            let use_auto_surround = this.use_auto_surround;
21991            this.set_use_autoclose(false);
21992            this.set_use_auto_surround(false);
21993            this.handle_input(text, window, cx);
21994            this.set_use_autoclose(use_autoclose);
21995            this.set_use_auto_surround(use_auto_surround);
21996
21997            if let Some(new_selected_range) = new_selected_range_utf16 {
21998                let snapshot = this.buffer.read(cx).read(cx);
21999                let new_selected_ranges = marked_ranges
22000                    .into_iter()
22001                    .map(|marked_range| {
22002                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22003                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22004                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22005                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22006                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22007                    })
22008                    .collect::<Vec<_>>();
22009
22010                drop(snapshot);
22011                this.change_selections(None, window, cx, |selections| {
22012                    selections.select_ranges(new_selected_ranges)
22013                });
22014            }
22015        });
22016
22017        self.ime_transaction = self.ime_transaction.or(transaction);
22018        if let Some(transaction) = self.ime_transaction {
22019            self.buffer.update(cx, |buffer, cx| {
22020                buffer.group_until_transaction(transaction, cx);
22021            });
22022        }
22023
22024        if self.text_highlights::<InputComposition>(cx).is_none() {
22025            self.ime_transaction.take();
22026        }
22027    }
22028
22029    fn bounds_for_range(
22030        &mut self,
22031        range_utf16: Range<usize>,
22032        element_bounds: gpui::Bounds<Pixels>,
22033        window: &mut Window,
22034        cx: &mut Context<Self>,
22035    ) -> Option<gpui::Bounds<Pixels>> {
22036        let text_layout_details = self.text_layout_details(window);
22037        let gpui::Size {
22038            width: em_width,
22039            height: line_height,
22040        } = self.character_size(window);
22041
22042        let snapshot = self.snapshot(window, cx);
22043        let scroll_position = snapshot.scroll_position();
22044        let scroll_left = scroll_position.x * em_width;
22045
22046        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22047        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22048            + self.gutter_dimensions.width
22049            + self.gutter_dimensions.margin;
22050        let y = line_height * (start.row().as_f32() - scroll_position.y);
22051
22052        Some(Bounds {
22053            origin: element_bounds.origin + point(x, y),
22054            size: size(em_width, line_height),
22055        })
22056    }
22057
22058    fn character_index_for_point(
22059        &mut self,
22060        point: gpui::Point<Pixels>,
22061        _window: &mut Window,
22062        _cx: &mut Context<Self>,
22063    ) -> Option<usize> {
22064        let position_map = self.last_position_map.as_ref()?;
22065        if !position_map.text_hitbox.contains(&point) {
22066            return None;
22067        }
22068        let display_point = position_map.point_for_position(point).previous_valid;
22069        let anchor = position_map
22070            .snapshot
22071            .display_point_to_anchor(display_point, Bias::Left);
22072        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22073        Some(utf16_offset.0)
22074    }
22075}
22076
22077trait SelectionExt {
22078    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22079    fn spanned_rows(
22080        &self,
22081        include_end_if_at_line_start: bool,
22082        map: &DisplaySnapshot,
22083    ) -> Range<MultiBufferRow>;
22084}
22085
22086impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22087    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22088        let start = self
22089            .start
22090            .to_point(&map.buffer_snapshot)
22091            .to_display_point(map);
22092        let end = self
22093            .end
22094            .to_point(&map.buffer_snapshot)
22095            .to_display_point(map);
22096        if self.reversed {
22097            end..start
22098        } else {
22099            start..end
22100        }
22101    }
22102
22103    fn spanned_rows(
22104        &self,
22105        include_end_if_at_line_start: bool,
22106        map: &DisplaySnapshot,
22107    ) -> Range<MultiBufferRow> {
22108        let start = self.start.to_point(&map.buffer_snapshot);
22109        let mut end = self.end.to_point(&map.buffer_snapshot);
22110        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22111            end.row -= 1;
22112        }
22113
22114        let buffer_start = map.prev_line_boundary(start).0;
22115        let buffer_end = map.next_line_boundary(end).0;
22116        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22117    }
22118}
22119
22120impl<T: InvalidationRegion> InvalidationStack<T> {
22121    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22122    where
22123        S: Clone + ToOffset,
22124    {
22125        while let Some(region) = self.last() {
22126            let all_selections_inside_invalidation_ranges =
22127                if selections.len() == region.ranges().len() {
22128                    selections
22129                        .iter()
22130                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22131                        .all(|(selection, invalidation_range)| {
22132                            let head = selection.head().to_offset(buffer);
22133                            invalidation_range.start <= head && invalidation_range.end >= head
22134                        })
22135                } else {
22136                    false
22137                };
22138
22139            if all_selections_inside_invalidation_ranges {
22140                break;
22141            } else {
22142                self.pop();
22143            }
22144        }
22145    }
22146}
22147
22148impl<T> Default for InvalidationStack<T> {
22149    fn default() -> Self {
22150        Self(Default::default())
22151    }
22152}
22153
22154impl<T> Deref for InvalidationStack<T> {
22155    type Target = Vec<T>;
22156
22157    fn deref(&self) -> &Self::Target {
22158        &self.0
22159    }
22160}
22161
22162impl<T> DerefMut for InvalidationStack<T> {
22163    fn deref_mut(&mut self) -> &mut Self::Target {
22164        &mut self.0
22165    }
22166}
22167
22168impl InvalidationRegion for SnippetState {
22169    fn ranges(&self) -> &[Range<Anchor>] {
22170        &self.ranges[self.active_index]
22171    }
22172}
22173
22174fn inline_completion_edit_text(
22175    current_snapshot: &BufferSnapshot,
22176    edits: &[(Range<Anchor>, String)],
22177    edit_preview: &EditPreview,
22178    include_deletions: bool,
22179    cx: &App,
22180) -> HighlightedText {
22181    let edits = edits
22182        .iter()
22183        .map(|(anchor, text)| {
22184            (
22185                anchor.start.text_anchor..anchor.end.text_anchor,
22186                text.clone(),
22187            )
22188        })
22189        .collect::<Vec<_>>();
22190
22191    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22192}
22193
22194pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22195    match severity {
22196        lsp::DiagnosticSeverity::ERROR => colors.error,
22197        lsp::DiagnosticSeverity::WARNING => colors.warning,
22198        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22199        lsp::DiagnosticSeverity::HINT => colors.info,
22200        _ => colors.ignored,
22201    }
22202}
22203
22204pub fn styled_runs_for_code_label<'a>(
22205    label: &'a CodeLabel,
22206    syntax_theme: &'a theme::SyntaxTheme,
22207) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22208    let fade_out = HighlightStyle {
22209        fade_out: Some(0.35),
22210        ..Default::default()
22211    };
22212
22213    let mut prev_end = label.filter_range.end;
22214    label
22215        .runs
22216        .iter()
22217        .enumerate()
22218        .flat_map(move |(ix, (range, highlight_id))| {
22219            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22220                style
22221            } else {
22222                return Default::default();
22223            };
22224            let mut muted_style = style;
22225            muted_style.highlight(fade_out);
22226
22227            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22228            if range.start >= label.filter_range.end {
22229                if range.start > prev_end {
22230                    runs.push((prev_end..range.start, fade_out));
22231                }
22232                runs.push((range.clone(), muted_style));
22233            } else if range.end <= label.filter_range.end {
22234                runs.push((range.clone(), style));
22235            } else {
22236                runs.push((range.start..label.filter_range.end, style));
22237                runs.push((label.filter_range.end..range.end, muted_style));
22238            }
22239            prev_end = cmp::max(prev_end, range.end);
22240
22241            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22242                runs.push((prev_end..label.text.len(), fade_out));
22243            }
22244
22245            runs
22246        })
22247}
22248
22249pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22250    let mut prev_index = 0;
22251    let mut prev_codepoint: Option<char> = None;
22252    text.char_indices()
22253        .chain([(text.len(), '\0')])
22254        .filter_map(move |(index, codepoint)| {
22255            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22256            let is_boundary = index == text.len()
22257                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22258                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22259            if is_boundary {
22260                let chunk = &text[prev_index..index];
22261                prev_index = index;
22262                Some(chunk)
22263            } else {
22264                None
22265            }
22266        })
22267}
22268
22269pub trait RangeToAnchorExt: Sized {
22270    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22271
22272    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22273        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22274        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22275    }
22276}
22277
22278impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22279    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22280        let start_offset = self.start.to_offset(snapshot);
22281        let end_offset = self.end.to_offset(snapshot);
22282        if start_offset == end_offset {
22283            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22284        } else {
22285            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22286        }
22287    }
22288}
22289
22290pub trait RowExt {
22291    fn as_f32(&self) -> f32;
22292
22293    fn next_row(&self) -> Self;
22294
22295    fn previous_row(&self) -> Self;
22296
22297    fn minus(&self, other: Self) -> u32;
22298}
22299
22300impl RowExt for DisplayRow {
22301    fn as_f32(&self) -> f32 {
22302        self.0 as f32
22303    }
22304
22305    fn next_row(&self) -> Self {
22306        Self(self.0 + 1)
22307    }
22308
22309    fn previous_row(&self) -> Self {
22310        Self(self.0.saturating_sub(1))
22311    }
22312
22313    fn minus(&self, other: Self) -> u32 {
22314        self.0 - other.0
22315    }
22316}
22317
22318impl RowExt for MultiBufferRow {
22319    fn as_f32(&self) -> f32 {
22320        self.0 as f32
22321    }
22322
22323    fn next_row(&self) -> Self {
22324        Self(self.0 + 1)
22325    }
22326
22327    fn previous_row(&self) -> Self {
22328        Self(self.0.saturating_sub(1))
22329    }
22330
22331    fn minus(&self, other: Self) -> u32 {
22332        self.0 - other.0
22333    }
22334}
22335
22336trait RowRangeExt {
22337    type Row;
22338
22339    fn len(&self) -> usize;
22340
22341    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22342}
22343
22344impl RowRangeExt for Range<MultiBufferRow> {
22345    type Row = MultiBufferRow;
22346
22347    fn len(&self) -> usize {
22348        (self.end.0 - self.start.0) as usize
22349    }
22350
22351    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22352        (self.start.0..self.end.0).map(MultiBufferRow)
22353    }
22354}
22355
22356impl RowRangeExt for Range<DisplayRow> {
22357    type Row = DisplayRow;
22358
22359    fn len(&self) -> usize {
22360        (self.end.0 - self.start.0) as usize
22361    }
22362
22363    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22364        (self.start.0..self.end.0).map(DisplayRow)
22365    }
22366}
22367
22368/// If select range has more than one line, we
22369/// just point the cursor to range.start.
22370fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22371    if range.start.row == range.end.row {
22372        range
22373    } else {
22374        range.start..range.start
22375    }
22376}
22377pub struct KillRing(ClipboardItem);
22378impl Global for KillRing {}
22379
22380const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22381
22382enum BreakpointPromptEditAction {
22383    Log,
22384    Condition,
22385    HitCondition,
22386}
22387
22388struct BreakpointPromptEditor {
22389    pub(crate) prompt: Entity<Editor>,
22390    editor: WeakEntity<Editor>,
22391    breakpoint_anchor: Anchor,
22392    breakpoint: Breakpoint,
22393    edit_action: BreakpointPromptEditAction,
22394    block_ids: HashSet<CustomBlockId>,
22395    editor_margins: Arc<Mutex<EditorMargins>>,
22396    _subscriptions: Vec<Subscription>,
22397}
22398
22399impl BreakpointPromptEditor {
22400    const MAX_LINES: u8 = 4;
22401
22402    fn new(
22403        editor: WeakEntity<Editor>,
22404        breakpoint_anchor: Anchor,
22405        breakpoint: Breakpoint,
22406        edit_action: BreakpointPromptEditAction,
22407        window: &mut Window,
22408        cx: &mut Context<Self>,
22409    ) -> Self {
22410        let base_text = match edit_action {
22411            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22412            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22413            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22414        }
22415        .map(|msg| msg.to_string())
22416        .unwrap_or_default();
22417
22418        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22419        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22420
22421        let prompt = cx.new(|cx| {
22422            let mut prompt = Editor::new(
22423                EditorMode::AutoHeight {
22424                    max_lines: Self::MAX_LINES as usize,
22425                },
22426                buffer,
22427                None,
22428                window,
22429                cx,
22430            );
22431            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22432            prompt.set_show_cursor_when_unfocused(false, cx);
22433            prompt.set_placeholder_text(
22434                match edit_action {
22435                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22436                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22437                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22438                },
22439                cx,
22440            );
22441
22442            prompt
22443        });
22444
22445        Self {
22446            prompt,
22447            editor,
22448            breakpoint_anchor,
22449            breakpoint,
22450            edit_action,
22451            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22452            block_ids: Default::default(),
22453            _subscriptions: vec![],
22454        }
22455    }
22456
22457    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22458        self.block_ids.extend(block_ids)
22459    }
22460
22461    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22462        if let Some(editor) = self.editor.upgrade() {
22463            let message = self
22464                .prompt
22465                .read(cx)
22466                .buffer
22467                .read(cx)
22468                .as_singleton()
22469                .expect("A multi buffer in breakpoint prompt isn't possible")
22470                .read(cx)
22471                .as_rope()
22472                .to_string();
22473
22474            editor.update(cx, |editor, cx| {
22475                editor.edit_breakpoint_at_anchor(
22476                    self.breakpoint_anchor,
22477                    self.breakpoint.clone(),
22478                    match self.edit_action {
22479                        BreakpointPromptEditAction::Log => {
22480                            BreakpointEditAction::EditLogMessage(message.into())
22481                        }
22482                        BreakpointPromptEditAction::Condition => {
22483                            BreakpointEditAction::EditCondition(message.into())
22484                        }
22485                        BreakpointPromptEditAction::HitCondition => {
22486                            BreakpointEditAction::EditHitCondition(message.into())
22487                        }
22488                    },
22489                    cx,
22490                );
22491
22492                editor.remove_blocks(self.block_ids.clone(), None, cx);
22493                cx.focus_self(window);
22494            });
22495        }
22496    }
22497
22498    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22499        self.editor
22500            .update(cx, |editor, cx| {
22501                editor.remove_blocks(self.block_ids.clone(), None, cx);
22502                window.focus(&editor.focus_handle);
22503            })
22504            .log_err();
22505    }
22506
22507    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22508        let settings = ThemeSettings::get_global(cx);
22509        let text_style = TextStyle {
22510            color: if self.prompt.read(cx).read_only(cx) {
22511                cx.theme().colors().text_disabled
22512            } else {
22513                cx.theme().colors().text
22514            },
22515            font_family: settings.buffer_font.family.clone(),
22516            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22517            font_size: settings.buffer_font_size(cx).into(),
22518            font_weight: settings.buffer_font.weight,
22519            line_height: relative(settings.buffer_line_height.value()),
22520            ..Default::default()
22521        };
22522        EditorElement::new(
22523            &self.prompt,
22524            EditorStyle {
22525                background: cx.theme().colors().editor_background,
22526                local_player: cx.theme().players().local(),
22527                text: text_style,
22528                ..Default::default()
22529            },
22530        )
22531    }
22532}
22533
22534impl Render for BreakpointPromptEditor {
22535    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22536        let editor_margins = *self.editor_margins.lock();
22537        let gutter_dimensions = editor_margins.gutter;
22538        h_flex()
22539            .key_context("Editor")
22540            .bg(cx.theme().colors().editor_background)
22541            .border_y_1()
22542            .border_color(cx.theme().status().info_border)
22543            .size_full()
22544            .py(window.line_height() / 2.5)
22545            .on_action(cx.listener(Self::confirm))
22546            .on_action(cx.listener(Self::cancel))
22547            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22548            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22549    }
22550}
22551
22552impl Focusable for BreakpointPromptEditor {
22553    fn focus_handle(&self, cx: &App) -> FocusHandle {
22554        self.prompt.focus_handle(cx)
22555    }
22556}
22557
22558fn all_edits_insertions_or_deletions(
22559    edits: &Vec<(Range<Anchor>, String)>,
22560    snapshot: &MultiBufferSnapshot,
22561) -> bool {
22562    let mut all_insertions = true;
22563    let mut all_deletions = true;
22564
22565    for (range, new_text) in edits.iter() {
22566        let range_is_empty = range.to_offset(&snapshot).is_empty();
22567        let text_is_empty = new_text.is_empty();
22568
22569        if range_is_empty != text_is_empty {
22570            if range_is_empty {
22571                all_deletions = false;
22572            } else {
22573                all_insertions = false;
22574            }
22575        } else {
22576            return false;
22577        }
22578
22579        if !all_insertions && !all_deletions {
22580            return false;
22581        }
22582    }
22583    all_insertions || all_deletions
22584}
22585
22586struct MissingEditPredictionKeybindingTooltip;
22587
22588impl Render for MissingEditPredictionKeybindingTooltip {
22589    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22590        ui::tooltip_container(window, cx, |container, _, cx| {
22591            container
22592                .flex_shrink_0()
22593                .max_w_80()
22594                .min_h(rems_from_px(124.))
22595                .justify_between()
22596                .child(
22597                    v_flex()
22598                        .flex_1()
22599                        .text_ui_sm(cx)
22600                        .child(Label::new("Conflict with Accept Keybinding"))
22601                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22602                )
22603                .child(
22604                    h_flex()
22605                        .pb_1()
22606                        .gap_1()
22607                        .items_end()
22608                        .w_full()
22609                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22610                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22611                        }))
22612                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22613                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22614                        })),
22615                )
22616        })
22617    }
22618}
22619
22620#[derive(Debug, Clone, Copy, PartialEq)]
22621pub struct LineHighlight {
22622    pub background: Background,
22623    pub border: Option<gpui::Hsla>,
22624    pub include_gutter: bool,
22625    pub type_id: Option<TypeId>,
22626}
22627
22628fn render_diff_hunk_controls(
22629    row: u32,
22630    status: &DiffHunkStatus,
22631    hunk_range: Range<Anchor>,
22632    is_created_file: bool,
22633    line_height: Pixels,
22634    editor: &Entity<Editor>,
22635    _window: &mut Window,
22636    cx: &mut App,
22637) -> AnyElement {
22638    h_flex()
22639        .h(line_height)
22640        .mr_1()
22641        .gap_1()
22642        .px_0p5()
22643        .pb_1()
22644        .border_x_1()
22645        .border_b_1()
22646        .border_color(cx.theme().colors().border_variant)
22647        .rounded_b_lg()
22648        .bg(cx.theme().colors().editor_background)
22649        .gap_1()
22650        .block_mouse_except_scroll()
22651        .shadow_md()
22652        .child(if status.has_secondary_hunk() {
22653            Button::new(("stage", row as u64), "Stage")
22654                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22655                .tooltip({
22656                    let focus_handle = editor.focus_handle(cx);
22657                    move |window, cx| {
22658                        Tooltip::for_action_in(
22659                            "Stage Hunk",
22660                            &::git::ToggleStaged,
22661                            &focus_handle,
22662                            window,
22663                            cx,
22664                        )
22665                    }
22666                })
22667                .on_click({
22668                    let editor = editor.clone();
22669                    move |_event, _window, cx| {
22670                        editor.update(cx, |editor, cx| {
22671                            editor.stage_or_unstage_diff_hunks(
22672                                true,
22673                                vec![hunk_range.start..hunk_range.start],
22674                                cx,
22675                            );
22676                        });
22677                    }
22678                })
22679        } else {
22680            Button::new(("unstage", row as u64), "Unstage")
22681                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22682                .tooltip({
22683                    let focus_handle = editor.focus_handle(cx);
22684                    move |window, cx| {
22685                        Tooltip::for_action_in(
22686                            "Unstage Hunk",
22687                            &::git::ToggleStaged,
22688                            &focus_handle,
22689                            window,
22690                            cx,
22691                        )
22692                    }
22693                })
22694                .on_click({
22695                    let editor = editor.clone();
22696                    move |_event, _window, cx| {
22697                        editor.update(cx, |editor, cx| {
22698                            editor.stage_or_unstage_diff_hunks(
22699                                false,
22700                                vec![hunk_range.start..hunk_range.start],
22701                                cx,
22702                            );
22703                        });
22704                    }
22705                })
22706        })
22707        .child(
22708            Button::new(("restore", row as u64), "Restore")
22709                .tooltip({
22710                    let focus_handle = editor.focus_handle(cx);
22711                    move |window, cx| {
22712                        Tooltip::for_action_in(
22713                            "Restore Hunk",
22714                            &::git::Restore,
22715                            &focus_handle,
22716                            window,
22717                            cx,
22718                        )
22719                    }
22720                })
22721                .on_click({
22722                    let editor = editor.clone();
22723                    move |_event, window, cx| {
22724                        editor.update(cx, |editor, cx| {
22725                            let snapshot = editor.snapshot(window, cx);
22726                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22727                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22728                        });
22729                    }
22730                })
22731                .disabled(is_created_file),
22732        )
22733        .when(
22734            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22735            |el| {
22736                el.child(
22737                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22738                        .shape(IconButtonShape::Square)
22739                        .icon_size(IconSize::Small)
22740                        // .disabled(!has_multiple_hunks)
22741                        .tooltip({
22742                            let focus_handle = editor.focus_handle(cx);
22743                            move |window, cx| {
22744                                Tooltip::for_action_in(
22745                                    "Next Hunk",
22746                                    &GoToHunk,
22747                                    &focus_handle,
22748                                    window,
22749                                    cx,
22750                                )
22751                            }
22752                        })
22753                        .on_click({
22754                            let editor = editor.clone();
22755                            move |_event, window, cx| {
22756                                editor.update(cx, |editor, cx| {
22757                                    let snapshot = editor.snapshot(window, cx);
22758                                    let position =
22759                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22760                                    editor.go_to_hunk_before_or_after_position(
22761                                        &snapshot,
22762                                        position,
22763                                        Direction::Next,
22764                                        window,
22765                                        cx,
22766                                    );
22767                                    editor.expand_selected_diff_hunks(cx);
22768                                });
22769                            }
22770                        }),
22771                )
22772                .child(
22773                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22774                        .shape(IconButtonShape::Square)
22775                        .icon_size(IconSize::Small)
22776                        // .disabled(!has_multiple_hunks)
22777                        .tooltip({
22778                            let focus_handle = editor.focus_handle(cx);
22779                            move |window, cx| {
22780                                Tooltip::for_action_in(
22781                                    "Previous Hunk",
22782                                    &GoToPreviousHunk,
22783                                    &focus_handle,
22784                                    window,
22785                                    cx,
22786                                )
22787                            }
22788                        })
22789                        .on_click({
22790                            let editor = editor.clone();
22791                            move |_event, window, cx| {
22792                                editor.update(cx, |editor, cx| {
22793                                    let snapshot = editor.snapshot(window, cx);
22794                                    let point =
22795                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22796                                    editor.go_to_hunk_before_or_after_position(
22797                                        &snapshot,
22798                                        point,
22799                                        Direction::Prev,
22800                                        window,
22801                                        cx,
22802                                    );
22803                                    editor.expand_selected_diff_hunks(cx);
22804                                });
22805                            }
22806                        }),
22807                )
22808            },
22809        )
22810        .into_any_element()
22811}