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        hide_drop_cursor: bool,
  922    },
  923}
  924
  925/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  926/// a breakpoint on them.
  927#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  928struct PhantomBreakpointIndicator {
  929    display_row: DisplayRow,
  930    /// There's a small debounce between hovering over the line and showing the indicator.
  931    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  932    is_active: bool,
  933    collides_with_existing_breakpoint: bool,
  934}
  935
  936/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  937///
  938/// See the [module level documentation](self) for more information.
  939pub struct Editor {
  940    focus_handle: FocusHandle,
  941    last_focused_descendant: Option<WeakFocusHandle>,
  942    /// The text buffer being edited
  943    buffer: Entity<MultiBuffer>,
  944    /// Map of how text in the buffer should be displayed.
  945    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  946    pub display_map: Entity<DisplayMap>,
  947    pub selections: SelectionsCollection,
  948    pub scroll_manager: ScrollManager,
  949    /// When inline assist editors are linked, they all render cursors because
  950    /// typing enters text into each of them, even the ones that aren't focused.
  951    pub(crate) show_cursor_when_unfocused: bool,
  952    columnar_selection_tail: Option<Anchor>,
  953    columnar_display_point: Option<DisplayPoint>,
  954    add_selections_state: Option<AddSelectionsState>,
  955    select_next_state: Option<SelectNextState>,
  956    select_prev_state: Option<SelectNextState>,
  957    selection_history: SelectionHistory,
  958    defer_selection_effects: bool,
  959    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  960    autoclose_regions: Vec<AutocloseRegion>,
  961    snippet_stack: InvalidationStack<SnippetState>,
  962    select_syntax_node_history: SelectSyntaxNodeHistory,
  963    ime_transaction: Option<TransactionId>,
  964    pub diagnostics_max_severity: DiagnosticSeverity,
  965    active_diagnostics: ActiveDiagnostic,
  966    show_inline_diagnostics: bool,
  967    inline_diagnostics_update: Task<()>,
  968    inline_diagnostics_enabled: bool,
  969    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  970    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  971    hard_wrap: Option<usize>,
  972
  973    // TODO: make this a access method
  974    pub project: Option<Entity<Project>>,
  975    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  976    completion_provider: Option<Rc<dyn CompletionProvider>>,
  977    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  978    blink_manager: Entity<BlinkManager>,
  979    show_cursor_names: bool,
  980    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  981    pub show_local_selections: bool,
  982    mode: EditorMode,
  983    show_breadcrumbs: bool,
  984    show_gutter: bool,
  985    show_scrollbars: ScrollbarAxes,
  986    minimap_visibility: MinimapVisibility,
  987    offset_content: bool,
  988    disable_expand_excerpt_buttons: bool,
  989    show_line_numbers: Option<bool>,
  990    use_relative_line_numbers: Option<bool>,
  991    show_git_diff_gutter: Option<bool>,
  992    show_code_actions: Option<bool>,
  993    show_runnables: Option<bool>,
  994    show_breakpoints: Option<bool>,
  995    show_wrap_guides: Option<bool>,
  996    show_indent_guides: Option<bool>,
  997    placeholder_text: Option<Arc<str>>,
  998    highlight_order: usize,
  999    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1000    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
 1001    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1002    scrollbar_marker_state: ScrollbarMarkerState,
 1003    active_indent_guides_state: ActiveIndentGuidesState,
 1004    nav_history: Option<ItemNavHistory>,
 1005    context_menu: RefCell<Option<CodeContextMenu>>,
 1006    context_menu_options: Option<ContextMenuOptions>,
 1007    mouse_context_menu: Option<MouseContextMenu>,
 1008    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1009    inline_blame_popover: Option<InlineBlamePopover>,
 1010    signature_help_state: SignatureHelpState,
 1011    auto_signature_help: Option<bool>,
 1012    find_all_references_task_sources: Vec<Anchor>,
 1013    next_completion_id: CompletionId,
 1014    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1015    code_actions_task: Option<Task<Result<()>>>,
 1016    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1017    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1018    document_highlights_task: Option<Task<()>>,
 1019    linked_editing_range_task: Option<Task<Option<()>>>,
 1020    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1021    pending_rename: Option<RenameState>,
 1022    searchable: bool,
 1023    cursor_shape: CursorShape,
 1024    current_line_highlight: Option<CurrentLineHighlight>,
 1025    collapse_matches: bool,
 1026    autoindent_mode: Option<AutoindentMode>,
 1027    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1028    input_enabled: bool,
 1029    use_modal_editing: bool,
 1030    read_only: bool,
 1031    leader_id: Option<CollaboratorId>,
 1032    remote_id: Option<ViewId>,
 1033    pub hover_state: HoverState,
 1034    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1035    gutter_hovered: bool,
 1036    hovered_link_state: Option<HoveredLinkState>,
 1037    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1038    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1039    active_inline_completion: Option<InlineCompletionState>,
 1040    /// Used to prevent flickering as the user types while the menu is open
 1041    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1042    edit_prediction_settings: EditPredictionSettings,
 1043    inline_completions_hidden_for_vim_mode: bool,
 1044    show_inline_completions_override: Option<bool>,
 1045    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1046    edit_prediction_preview: EditPredictionPreview,
 1047    edit_prediction_indent_conflict: bool,
 1048    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1049    inlay_hint_cache: InlayHintCache,
 1050    next_inlay_id: usize,
 1051    _subscriptions: Vec<Subscription>,
 1052    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1053    gutter_dimensions: GutterDimensions,
 1054    style: Option<EditorStyle>,
 1055    text_style_refinement: Option<TextStyleRefinement>,
 1056    next_editor_action_id: EditorActionId,
 1057    editor_actions:
 1058        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1059    use_autoclose: bool,
 1060    use_auto_surround: bool,
 1061    auto_replace_emoji_shortcode: bool,
 1062    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1063    show_git_blame_gutter: bool,
 1064    show_git_blame_inline: bool,
 1065    show_git_blame_inline_delay_task: Option<Task<()>>,
 1066    git_blame_inline_enabled: bool,
 1067    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1068    serialize_dirty_buffers: bool,
 1069    show_selection_menu: Option<bool>,
 1070    blame: Option<Entity<GitBlame>>,
 1071    blame_subscription: Option<Subscription>,
 1072    custom_context_menu: Option<
 1073        Box<
 1074            dyn 'static
 1075                + Fn(
 1076                    &mut Self,
 1077                    DisplayPoint,
 1078                    &mut Window,
 1079                    &mut Context<Self>,
 1080                ) -> Option<Entity<ui::ContextMenu>>,
 1081        >,
 1082    >,
 1083    last_bounds: Option<Bounds<Pixels>>,
 1084    last_position_map: Option<Rc<PositionMap>>,
 1085    expect_bounds_change: Option<Bounds<Pixels>>,
 1086    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1087    tasks_update_task: Option<Task<()>>,
 1088    breakpoint_store: Option<Entity<BreakpointStore>>,
 1089    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1090    pull_diagnostics_task: Task<()>,
 1091    in_project_search: bool,
 1092    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1093    breadcrumb_header: Option<String>,
 1094    focused_block: Option<FocusedBlock>,
 1095    next_scroll_position: NextScrollCursorCenterTopBottom,
 1096    addons: HashMap<TypeId, Box<dyn Addon>>,
 1097    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1098    load_diff_task: Option<Shared<Task<()>>>,
 1099    /// Whether we are temporarily displaying a diff other than git's
 1100    temporary_diff_override: bool,
 1101    selection_mark_mode: bool,
 1102    toggle_fold_multiple_buffers: Task<()>,
 1103    _scroll_cursor_center_top_bottom_task: Task<()>,
 1104    serialize_selections: Task<()>,
 1105    serialize_folds: Task<()>,
 1106    mouse_cursor_hidden: bool,
 1107    minimap: Option<Entity<Self>>,
 1108    hide_mouse_mode: HideMouseMode,
 1109    pub change_list: ChangeList,
 1110    inline_value_cache: InlineValueCache,
 1111    selection_drag_state: SelectionDragState,
 1112    drag_and_drop_selection_enabled: bool,
 1113}
 1114
 1115#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1116enum NextScrollCursorCenterTopBottom {
 1117    #[default]
 1118    Center,
 1119    Top,
 1120    Bottom,
 1121}
 1122
 1123impl NextScrollCursorCenterTopBottom {
 1124    fn next(&self) -> Self {
 1125        match self {
 1126            Self::Center => Self::Top,
 1127            Self::Top => Self::Bottom,
 1128            Self::Bottom => Self::Center,
 1129        }
 1130    }
 1131}
 1132
 1133#[derive(Clone)]
 1134pub struct EditorSnapshot {
 1135    pub mode: EditorMode,
 1136    show_gutter: bool,
 1137    show_line_numbers: Option<bool>,
 1138    show_git_diff_gutter: Option<bool>,
 1139    show_code_actions: Option<bool>,
 1140    show_runnables: Option<bool>,
 1141    show_breakpoints: Option<bool>,
 1142    git_blame_gutter_max_author_length: Option<usize>,
 1143    pub display_snapshot: DisplaySnapshot,
 1144    pub placeholder_text: Option<Arc<str>>,
 1145    is_focused: bool,
 1146    scroll_anchor: ScrollAnchor,
 1147    ongoing_scroll: OngoingScroll,
 1148    current_line_highlight: CurrentLineHighlight,
 1149    gutter_hovered: bool,
 1150}
 1151
 1152#[derive(Default, Debug, Clone, Copy)]
 1153pub struct GutterDimensions {
 1154    pub left_padding: Pixels,
 1155    pub right_padding: Pixels,
 1156    pub width: Pixels,
 1157    pub margin: Pixels,
 1158    pub git_blame_entries_width: Option<Pixels>,
 1159}
 1160
 1161impl GutterDimensions {
 1162    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1163        Self {
 1164            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1165            ..Default::default()
 1166        }
 1167    }
 1168
 1169    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1170        -cx.text_system().descent(font_id, font_size)
 1171    }
 1172    /// The full width of the space taken up by the gutter.
 1173    pub fn full_width(&self) -> Pixels {
 1174        self.margin + self.width
 1175    }
 1176
 1177    /// The width of the space reserved for the fold indicators,
 1178    /// use alongside 'justify_end' and `gutter_width` to
 1179    /// right align content with the line numbers
 1180    pub fn fold_area_width(&self) -> Pixels {
 1181        self.margin + self.right_padding
 1182    }
 1183}
 1184
 1185#[derive(Debug)]
 1186pub struct RemoteSelection {
 1187    pub replica_id: ReplicaId,
 1188    pub selection: Selection<Anchor>,
 1189    pub cursor_shape: CursorShape,
 1190    pub collaborator_id: CollaboratorId,
 1191    pub line_mode: bool,
 1192    pub user_name: Option<SharedString>,
 1193    pub color: PlayerColor,
 1194}
 1195
 1196#[derive(Clone, Debug)]
 1197struct SelectionHistoryEntry {
 1198    selections: Arc<[Selection<Anchor>]>,
 1199    select_next_state: Option<SelectNextState>,
 1200    select_prev_state: Option<SelectNextState>,
 1201    add_selections_state: Option<AddSelectionsState>,
 1202}
 1203
 1204#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1205enum SelectionHistoryMode {
 1206    Normal,
 1207    Undoing,
 1208    Redoing,
 1209    Skipping,
 1210}
 1211
 1212#[derive(Clone, PartialEq, Eq, Hash)]
 1213struct HoveredCursor {
 1214    replica_id: u16,
 1215    selection_id: usize,
 1216}
 1217
 1218impl Default for SelectionHistoryMode {
 1219    fn default() -> Self {
 1220        Self::Normal
 1221    }
 1222}
 1223
 1224struct DeferredSelectionEffectsState {
 1225    changed: bool,
 1226    should_update_completions: bool,
 1227    autoscroll: Option<Autoscroll>,
 1228    old_cursor_position: Anchor,
 1229    history_entry: SelectionHistoryEntry,
 1230}
 1231
 1232#[derive(Default)]
 1233struct SelectionHistory {
 1234    #[allow(clippy::type_complexity)]
 1235    selections_by_transaction:
 1236        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1237    mode: SelectionHistoryMode,
 1238    undo_stack: VecDeque<SelectionHistoryEntry>,
 1239    redo_stack: VecDeque<SelectionHistoryEntry>,
 1240}
 1241
 1242impl SelectionHistory {
 1243    #[track_caller]
 1244    fn insert_transaction(
 1245        &mut self,
 1246        transaction_id: TransactionId,
 1247        selections: Arc<[Selection<Anchor>]>,
 1248    ) {
 1249        if selections.is_empty() {
 1250            log::error!(
 1251                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1252                std::panic::Location::caller()
 1253            );
 1254            return;
 1255        }
 1256        self.selections_by_transaction
 1257            .insert(transaction_id, (selections, None));
 1258    }
 1259
 1260    #[allow(clippy::type_complexity)]
 1261    fn transaction(
 1262        &self,
 1263        transaction_id: TransactionId,
 1264    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1265        self.selections_by_transaction.get(&transaction_id)
 1266    }
 1267
 1268    #[allow(clippy::type_complexity)]
 1269    fn transaction_mut(
 1270        &mut self,
 1271        transaction_id: TransactionId,
 1272    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1273        self.selections_by_transaction.get_mut(&transaction_id)
 1274    }
 1275
 1276    fn push(&mut self, entry: SelectionHistoryEntry) {
 1277        if !entry.selections.is_empty() {
 1278            match self.mode {
 1279                SelectionHistoryMode::Normal => {
 1280                    self.push_undo(entry);
 1281                    self.redo_stack.clear();
 1282                }
 1283                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1284                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1285                SelectionHistoryMode::Skipping => {}
 1286            }
 1287        }
 1288    }
 1289
 1290    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1291        if self
 1292            .undo_stack
 1293            .back()
 1294            .map_or(true, |e| e.selections != entry.selections)
 1295        {
 1296            self.undo_stack.push_back(entry);
 1297            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1298                self.undo_stack.pop_front();
 1299            }
 1300        }
 1301    }
 1302
 1303    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1304        if self
 1305            .redo_stack
 1306            .back()
 1307            .map_or(true, |e| e.selections != entry.selections)
 1308        {
 1309            self.redo_stack.push_back(entry);
 1310            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1311                self.redo_stack.pop_front();
 1312            }
 1313        }
 1314    }
 1315}
 1316
 1317#[derive(Clone, Copy)]
 1318pub struct RowHighlightOptions {
 1319    pub autoscroll: bool,
 1320    pub include_gutter: bool,
 1321}
 1322
 1323impl Default for RowHighlightOptions {
 1324    fn default() -> Self {
 1325        Self {
 1326            autoscroll: Default::default(),
 1327            include_gutter: true,
 1328        }
 1329    }
 1330}
 1331
 1332struct RowHighlight {
 1333    index: usize,
 1334    range: Range<Anchor>,
 1335    color: Hsla,
 1336    options: RowHighlightOptions,
 1337    type_id: TypeId,
 1338}
 1339
 1340#[derive(Clone, Debug)]
 1341struct AddSelectionsState {
 1342    groups: Vec<AddSelectionsGroup>,
 1343}
 1344
 1345#[derive(Clone, Debug)]
 1346struct AddSelectionsGroup {
 1347    above: bool,
 1348    stack: Vec<usize>,
 1349}
 1350
 1351#[derive(Clone)]
 1352struct SelectNextState {
 1353    query: AhoCorasick,
 1354    wordwise: bool,
 1355    done: bool,
 1356}
 1357
 1358impl std::fmt::Debug for SelectNextState {
 1359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1360        f.debug_struct(std::any::type_name::<Self>())
 1361            .field("wordwise", &self.wordwise)
 1362            .field("done", &self.done)
 1363            .finish()
 1364    }
 1365}
 1366
 1367#[derive(Debug)]
 1368struct AutocloseRegion {
 1369    selection_id: usize,
 1370    range: Range<Anchor>,
 1371    pair: BracketPair,
 1372}
 1373
 1374#[derive(Debug)]
 1375struct SnippetState {
 1376    ranges: Vec<Vec<Range<Anchor>>>,
 1377    active_index: usize,
 1378    choices: Vec<Option<Vec<String>>>,
 1379}
 1380
 1381#[doc(hidden)]
 1382pub struct RenameState {
 1383    pub range: Range<Anchor>,
 1384    pub old_name: Arc<str>,
 1385    pub editor: Entity<Editor>,
 1386    block_id: CustomBlockId,
 1387}
 1388
 1389struct InvalidationStack<T>(Vec<T>);
 1390
 1391struct RegisteredInlineCompletionProvider {
 1392    provider: Arc<dyn InlineCompletionProviderHandle>,
 1393    _subscription: Subscription,
 1394}
 1395
 1396#[derive(Debug, PartialEq, Eq)]
 1397pub struct ActiveDiagnosticGroup {
 1398    pub active_range: Range<Anchor>,
 1399    pub active_message: String,
 1400    pub group_id: usize,
 1401    pub blocks: HashSet<CustomBlockId>,
 1402}
 1403
 1404#[derive(Debug, PartialEq, Eq)]
 1405
 1406pub(crate) enum ActiveDiagnostic {
 1407    None,
 1408    All,
 1409    Group(ActiveDiagnosticGroup),
 1410}
 1411
 1412#[derive(Serialize, Deserialize, Clone, Debug)]
 1413pub struct ClipboardSelection {
 1414    /// The number of bytes in this selection.
 1415    pub len: usize,
 1416    /// Whether this was a full-line selection.
 1417    pub is_entire_line: bool,
 1418    /// The indentation of the first line when this content was originally copied.
 1419    pub first_line_indent: u32,
 1420}
 1421
 1422// selections, scroll behavior, was newest selection reversed
 1423type SelectSyntaxNodeHistoryState = (
 1424    Box<[Selection<usize>]>,
 1425    SelectSyntaxNodeScrollBehavior,
 1426    bool,
 1427);
 1428
 1429#[derive(Default)]
 1430struct SelectSyntaxNodeHistory {
 1431    stack: Vec<SelectSyntaxNodeHistoryState>,
 1432    // disable temporarily to allow changing selections without losing the stack
 1433    pub disable_clearing: bool,
 1434}
 1435
 1436impl SelectSyntaxNodeHistory {
 1437    pub fn try_clear(&mut self) {
 1438        if !self.disable_clearing {
 1439            self.stack.clear();
 1440        }
 1441    }
 1442
 1443    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1444        self.stack.push(selection);
 1445    }
 1446
 1447    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1448        self.stack.pop()
 1449    }
 1450}
 1451
 1452enum SelectSyntaxNodeScrollBehavior {
 1453    CursorTop,
 1454    FitSelection,
 1455    CursorBottom,
 1456}
 1457
 1458#[derive(Debug)]
 1459pub(crate) struct NavigationData {
 1460    cursor_anchor: Anchor,
 1461    cursor_position: Point,
 1462    scroll_anchor: ScrollAnchor,
 1463    scroll_top_row: u32,
 1464}
 1465
 1466#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1467pub enum GotoDefinitionKind {
 1468    Symbol,
 1469    Declaration,
 1470    Type,
 1471    Implementation,
 1472}
 1473
 1474#[derive(Debug, Clone)]
 1475enum InlayHintRefreshReason {
 1476    ModifiersChanged(bool),
 1477    Toggle(bool),
 1478    SettingsChange(InlayHintSettings),
 1479    NewLinesShown,
 1480    BufferEdited(HashSet<Arc<Language>>),
 1481    RefreshRequested,
 1482    ExcerptsRemoved(Vec<ExcerptId>),
 1483}
 1484
 1485impl InlayHintRefreshReason {
 1486    fn description(&self) -> &'static str {
 1487        match self {
 1488            Self::ModifiersChanged(_) => "modifiers changed",
 1489            Self::Toggle(_) => "toggle",
 1490            Self::SettingsChange(_) => "settings change",
 1491            Self::NewLinesShown => "new lines shown",
 1492            Self::BufferEdited(_) => "buffer edited",
 1493            Self::RefreshRequested => "refresh requested",
 1494            Self::ExcerptsRemoved(_) => "excerpts removed",
 1495        }
 1496    }
 1497}
 1498
 1499pub enum FormatTarget {
 1500    Buffers,
 1501    Ranges(Vec<Range<MultiBufferPoint>>),
 1502}
 1503
 1504pub(crate) struct FocusedBlock {
 1505    id: BlockId,
 1506    focus_handle: WeakFocusHandle,
 1507}
 1508
 1509#[derive(Clone)]
 1510enum JumpData {
 1511    MultiBufferRow {
 1512        row: MultiBufferRow,
 1513        line_offset_from_top: u32,
 1514    },
 1515    MultiBufferPoint {
 1516        excerpt_id: ExcerptId,
 1517        position: Point,
 1518        anchor: text::Anchor,
 1519        line_offset_from_top: u32,
 1520    },
 1521}
 1522
 1523pub enum MultibufferSelectionMode {
 1524    First,
 1525    All,
 1526}
 1527
 1528#[derive(Clone, Copy, Debug, Default)]
 1529pub struct RewrapOptions {
 1530    pub override_language_settings: bool,
 1531    pub preserve_existing_whitespace: bool,
 1532}
 1533
 1534impl Editor {
 1535    pub fn single_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(
 1539            EditorMode::SingleLine { auto_width: false },
 1540            buffer,
 1541            None,
 1542            window,
 1543            cx,
 1544        )
 1545    }
 1546
 1547    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1548        let buffer = cx.new(|cx| Buffer::local("", cx));
 1549        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1550        Self::new(EditorMode::full(), buffer, None, window, cx)
 1551    }
 1552
 1553    pub fn auto_width(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::SingleLine { auto_width: true },
 1558            buffer,
 1559            None,
 1560            window,
 1561            cx,
 1562        )
 1563    }
 1564
 1565    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1566        let buffer = cx.new(|cx| Buffer::local("", cx));
 1567        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1568        Self::new(
 1569            EditorMode::AutoHeight { max_lines },
 1570            buffer,
 1571            None,
 1572            window,
 1573            cx,
 1574        )
 1575    }
 1576
 1577    pub fn for_buffer(
 1578        buffer: Entity<Buffer>,
 1579        project: Option<Entity<Project>>,
 1580        window: &mut Window,
 1581        cx: &mut Context<Self>,
 1582    ) -> Self {
 1583        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1584        Self::new(EditorMode::full(), buffer, project, window, cx)
 1585    }
 1586
 1587    pub fn for_multibuffer(
 1588        buffer: Entity<MultiBuffer>,
 1589        project: Option<Entity<Project>>,
 1590        window: &mut Window,
 1591        cx: &mut Context<Self>,
 1592    ) -> Self {
 1593        Self::new(EditorMode::full(), buffer, project, window, cx)
 1594    }
 1595
 1596    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1597        let mut clone = Self::new(
 1598            self.mode.clone(),
 1599            self.buffer.clone(),
 1600            self.project.clone(),
 1601            window,
 1602            cx,
 1603        );
 1604        self.display_map.update(cx, |display_map, cx| {
 1605            let snapshot = display_map.snapshot(cx);
 1606            clone.display_map.update(cx, |display_map, cx| {
 1607                display_map.set_state(&snapshot, cx);
 1608            });
 1609        });
 1610        clone.folds_did_change(cx);
 1611        clone.selections.clone_state(&self.selections);
 1612        clone.scroll_manager.clone_state(&self.scroll_manager);
 1613        clone.searchable = self.searchable;
 1614        clone.read_only = self.read_only;
 1615        clone
 1616    }
 1617
 1618    pub fn new(
 1619        mode: EditorMode,
 1620        buffer: Entity<MultiBuffer>,
 1621        project: Option<Entity<Project>>,
 1622        window: &mut Window,
 1623        cx: &mut Context<Self>,
 1624    ) -> Self {
 1625        Editor::new_internal(mode, buffer, project, None, window, cx)
 1626    }
 1627
 1628    fn new_internal(
 1629        mode: EditorMode,
 1630        buffer: Entity<MultiBuffer>,
 1631        project: Option<Entity<Project>>,
 1632        display_map: Option<Entity<DisplayMap>>,
 1633        window: &mut Window,
 1634        cx: &mut Context<Self>,
 1635    ) -> Self {
 1636        debug_assert!(
 1637            display_map.is_none() || mode.is_minimap(),
 1638            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1639        );
 1640
 1641        let full_mode = mode.is_full();
 1642        let diagnostics_max_severity = if full_mode {
 1643            EditorSettings::get_global(cx)
 1644                .diagnostics_max_severity
 1645                .unwrap_or(DiagnosticSeverity::Hint)
 1646        } else {
 1647            DiagnosticSeverity::Off
 1648        };
 1649        let style = window.text_style();
 1650        let font_size = style.font_size.to_pixels(window.rem_size());
 1651        let editor = cx.entity().downgrade();
 1652        let fold_placeholder = FoldPlaceholder {
 1653            constrain_width: true,
 1654            render: Arc::new(move |fold_id, fold_range, cx| {
 1655                let editor = editor.clone();
 1656                div()
 1657                    .id(fold_id)
 1658                    .bg(cx.theme().colors().ghost_element_background)
 1659                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1660                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1661                    .rounded_xs()
 1662                    .size_full()
 1663                    .cursor_pointer()
 1664                    .child("")
 1665                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1666                    .on_click(move |_, _window, cx| {
 1667                        editor
 1668                            .update(cx, |editor, cx| {
 1669                                editor.unfold_ranges(
 1670                                    &[fold_range.start..fold_range.end],
 1671                                    true,
 1672                                    false,
 1673                                    cx,
 1674                                );
 1675                                cx.stop_propagation();
 1676                            })
 1677                            .ok();
 1678                    })
 1679                    .into_any()
 1680            }),
 1681            merge_adjacent: true,
 1682            ..FoldPlaceholder::default()
 1683        };
 1684        let display_map = display_map.unwrap_or_else(|| {
 1685            cx.new(|cx| {
 1686                DisplayMap::new(
 1687                    buffer.clone(),
 1688                    style.font(),
 1689                    font_size,
 1690                    None,
 1691                    FILE_HEADER_HEIGHT,
 1692                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1693                    fold_placeholder,
 1694                    diagnostics_max_severity,
 1695                    cx,
 1696                )
 1697            })
 1698        });
 1699
 1700        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1701
 1702        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1703
 1704        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1705            .then(|| language_settings::SoftWrap::None);
 1706
 1707        let mut project_subscriptions = Vec::new();
 1708        if mode.is_full() {
 1709            if let Some(project) = project.as_ref() {
 1710                project_subscriptions.push(cx.subscribe_in(
 1711                    project,
 1712                    window,
 1713                    |editor, _, event, window, cx| match event {
 1714                        project::Event::RefreshCodeLens => {
 1715                            // we always query lens with actions, without storing them, always refreshing them
 1716                        }
 1717                        project::Event::RefreshInlayHints => {
 1718                            editor
 1719                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1720                        }
 1721                        project::Event::LanguageServerAdded(..)
 1722                        | project::Event::LanguageServerRemoved(..) => {
 1723                            if editor.tasks_update_task.is_none() {
 1724                                editor.tasks_update_task =
 1725                                    Some(editor.refresh_runnables(window, cx));
 1726                            }
 1727                            editor.pull_diagnostics(None, window, cx);
 1728                        }
 1729                        project::Event::SnippetEdit(id, snippet_edits) => {
 1730                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1731                                let focus_handle = editor.focus_handle(cx);
 1732                                if focus_handle.is_focused(window) {
 1733                                    let snapshot = buffer.read(cx).snapshot();
 1734                                    for (range, snippet) in snippet_edits {
 1735                                        let editor_range =
 1736                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1737                                        editor
 1738                                            .insert_snippet(
 1739                                                &[editor_range],
 1740                                                snippet.clone(),
 1741                                                window,
 1742                                                cx,
 1743                                            )
 1744                                            .ok();
 1745                                    }
 1746                                }
 1747                            }
 1748                        }
 1749                        _ => {}
 1750                    },
 1751                ));
 1752                if let Some(task_inventory) = project
 1753                    .read(cx)
 1754                    .task_store()
 1755                    .read(cx)
 1756                    .task_inventory()
 1757                    .cloned()
 1758                {
 1759                    project_subscriptions.push(cx.observe_in(
 1760                        &task_inventory,
 1761                        window,
 1762                        |editor, _, window, cx| {
 1763                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1764                        },
 1765                    ));
 1766                };
 1767
 1768                project_subscriptions.push(cx.subscribe_in(
 1769                    &project.read(cx).breakpoint_store(),
 1770                    window,
 1771                    |editor, _, event, window, cx| match event {
 1772                        BreakpointStoreEvent::ClearDebugLines => {
 1773                            editor.clear_row_highlights::<ActiveDebugLine>();
 1774                            editor.refresh_inline_values(cx);
 1775                        }
 1776                        BreakpointStoreEvent::SetDebugLine => {
 1777                            if editor.go_to_active_debug_line(window, cx) {
 1778                                cx.stop_propagation();
 1779                            }
 1780
 1781                            editor.refresh_inline_values(cx);
 1782                        }
 1783                        _ => {}
 1784                    },
 1785                ));
 1786            }
 1787        }
 1788
 1789        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1790
 1791        let inlay_hint_settings =
 1792            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1793        let focus_handle = cx.focus_handle();
 1794        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1795            .detach();
 1796        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1797            .detach();
 1798        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1799            .detach();
 1800        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1801            .detach();
 1802        cx.observe_pending_input(window, Self::observe_pending_input)
 1803            .detach();
 1804
 1805        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1806            Some(false)
 1807        } else {
 1808            None
 1809        };
 1810
 1811        let breakpoint_store = match (&mode, project.as_ref()) {
 1812            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1813            _ => None,
 1814        };
 1815
 1816        let mut code_action_providers = Vec::new();
 1817        let mut load_uncommitted_diff = None;
 1818        if let Some(project) = project.clone() {
 1819            load_uncommitted_diff = Some(
 1820                update_uncommitted_diff_for_buffer(
 1821                    cx.entity(),
 1822                    &project,
 1823                    buffer.read(cx).all_buffers(),
 1824                    buffer.clone(),
 1825                    cx,
 1826                )
 1827                .shared(),
 1828            );
 1829            code_action_providers.push(Rc::new(project) as Rc<_>);
 1830        }
 1831
 1832        let mut editor = Self {
 1833            focus_handle,
 1834            show_cursor_when_unfocused: false,
 1835            last_focused_descendant: None,
 1836            buffer: buffer.clone(),
 1837            display_map: display_map.clone(),
 1838            selections,
 1839            scroll_manager: ScrollManager::new(cx),
 1840            columnar_selection_tail: None,
 1841            columnar_display_point: None,
 1842            add_selections_state: None,
 1843            select_next_state: None,
 1844            select_prev_state: None,
 1845            selection_history: SelectionHistory::default(),
 1846            defer_selection_effects: false,
 1847            deferred_selection_effects_state: None,
 1848            autoclose_regions: Vec::new(),
 1849            snippet_stack: InvalidationStack::default(),
 1850            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1851            ime_transaction: None,
 1852            active_diagnostics: ActiveDiagnostic::None,
 1853            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1854            inline_diagnostics_update: Task::ready(()),
 1855            inline_diagnostics: Vec::new(),
 1856            soft_wrap_mode_override,
 1857            diagnostics_max_severity,
 1858            hard_wrap: None,
 1859            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1860            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1861            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1862            project,
 1863            blink_manager: blink_manager.clone(),
 1864            show_local_selections: true,
 1865            show_scrollbars: ScrollbarAxes {
 1866                horizontal: full_mode,
 1867                vertical: full_mode,
 1868            },
 1869            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1870            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1871            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1872            show_gutter: mode.is_full(),
 1873            show_line_numbers: None,
 1874            use_relative_line_numbers: None,
 1875            disable_expand_excerpt_buttons: false,
 1876            show_git_diff_gutter: None,
 1877            show_code_actions: None,
 1878            show_runnables: None,
 1879            show_breakpoints: None,
 1880            show_wrap_guides: None,
 1881            show_indent_guides,
 1882            placeholder_text: None,
 1883            highlight_order: 0,
 1884            highlighted_rows: HashMap::default(),
 1885            background_highlights: TreeMap::default(),
 1886            gutter_highlights: TreeMap::default(),
 1887            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1888            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1889            nav_history: None,
 1890            context_menu: RefCell::new(None),
 1891            context_menu_options: None,
 1892            mouse_context_menu: None,
 1893            completion_tasks: Vec::new(),
 1894            inline_blame_popover: None,
 1895            signature_help_state: SignatureHelpState::default(),
 1896            auto_signature_help: None,
 1897            find_all_references_task_sources: Vec::new(),
 1898            next_completion_id: 0,
 1899            next_inlay_id: 0,
 1900            code_action_providers,
 1901            available_code_actions: None,
 1902            code_actions_task: None,
 1903            quick_selection_highlight_task: None,
 1904            debounced_selection_highlight_task: None,
 1905            document_highlights_task: None,
 1906            linked_editing_range_task: None,
 1907            pending_rename: None,
 1908            searchable: true,
 1909            cursor_shape: EditorSettings::get_global(cx)
 1910                .cursor_shape
 1911                .unwrap_or_default(),
 1912            current_line_highlight: None,
 1913            autoindent_mode: Some(AutoindentMode::EachLine),
 1914            collapse_matches: false,
 1915            workspace: None,
 1916            input_enabled: true,
 1917            use_modal_editing: mode.is_full(),
 1918            read_only: mode.is_minimap(),
 1919            use_autoclose: true,
 1920            use_auto_surround: true,
 1921            auto_replace_emoji_shortcode: false,
 1922            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1923            leader_id: None,
 1924            remote_id: None,
 1925            hover_state: HoverState::default(),
 1926            pending_mouse_down: None,
 1927            hovered_link_state: None,
 1928            edit_prediction_provider: None,
 1929            active_inline_completion: None,
 1930            stale_inline_completion_in_menu: None,
 1931            edit_prediction_preview: EditPredictionPreview::Inactive {
 1932                released_too_fast: false,
 1933            },
 1934            inline_diagnostics_enabled: mode.is_full(),
 1935            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1936            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1937
 1938            gutter_hovered: false,
 1939            pixel_position_of_newest_cursor: None,
 1940            last_bounds: None,
 1941            last_position_map: None,
 1942            expect_bounds_change: None,
 1943            gutter_dimensions: GutterDimensions::default(),
 1944            style: None,
 1945            show_cursor_names: false,
 1946            hovered_cursors: HashMap::default(),
 1947            next_editor_action_id: EditorActionId::default(),
 1948            editor_actions: Rc::default(),
 1949            inline_completions_hidden_for_vim_mode: false,
 1950            show_inline_completions_override: None,
 1951            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1952            edit_prediction_settings: EditPredictionSettings::Disabled,
 1953            edit_prediction_indent_conflict: false,
 1954            edit_prediction_requires_modifier_in_indent_conflict: true,
 1955            custom_context_menu: None,
 1956            show_git_blame_gutter: false,
 1957            show_git_blame_inline: false,
 1958            show_selection_menu: None,
 1959            show_git_blame_inline_delay_task: None,
 1960            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1961            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1962            serialize_dirty_buffers: !mode.is_minimap()
 1963                && ProjectSettings::get_global(cx)
 1964                    .session
 1965                    .restore_unsaved_buffers,
 1966            blame: None,
 1967            blame_subscription: None,
 1968            tasks: BTreeMap::default(),
 1969
 1970            breakpoint_store,
 1971            gutter_breakpoint_indicator: (None, None),
 1972            _subscriptions: vec![
 1973                cx.observe(&buffer, Self::on_buffer_changed),
 1974                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1975                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1976                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1977                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1978                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1979                cx.observe_window_activation(window, |editor, window, cx| {
 1980                    let active = window.is_window_active();
 1981                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1982                        if active {
 1983                            blink_manager.enable(cx);
 1984                        } else {
 1985                            blink_manager.disable(cx);
 1986                        }
 1987                    });
 1988                    if active {
 1989                        editor.show_mouse_cursor();
 1990                    }
 1991                }),
 1992            ],
 1993            tasks_update_task: None,
 1994            pull_diagnostics_task: Task::ready(()),
 1995            linked_edit_ranges: Default::default(),
 1996            in_project_search: false,
 1997            previous_search_ranges: None,
 1998            breadcrumb_header: None,
 1999            focused_block: None,
 2000            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2001            addons: HashMap::default(),
 2002            registered_buffers: HashMap::default(),
 2003            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2004            selection_mark_mode: false,
 2005            toggle_fold_multiple_buffers: Task::ready(()),
 2006            serialize_selections: Task::ready(()),
 2007            serialize_folds: Task::ready(()),
 2008            text_style_refinement: None,
 2009            load_diff_task: load_uncommitted_diff,
 2010            temporary_diff_override: false,
 2011            mouse_cursor_hidden: false,
 2012            minimap: None,
 2013            hide_mouse_mode: EditorSettings::get_global(cx)
 2014                .hide_mouse
 2015                .unwrap_or_default(),
 2016            change_list: ChangeList::new(),
 2017            mode,
 2018            selection_drag_state: SelectionDragState::None,
 2019            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2020        };
 2021        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2022            editor
 2023                ._subscriptions
 2024                .push(cx.observe(breakpoints, |_, _, cx| {
 2025                    cx.notify();
 2026                }));
 2027        }
 2028        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2029        editor._subscriptions.extend(project_subscriptions);
 2030
 2031        editor._subscriptions.push(cx.subscribe_in(
 2032            &cx.entity(),
 2033            window,
 2034            |editor, _, e: &EditorEvent, window, cx| match e {
 2035                EditorEvent::ScrollPositionChanged { local, .. } => {
 2036                    if *local {
 2037                        let new_anchor = editor.scroll_manager.anchor();
 2038                        let snapshot = editor.snapshot(window, cx);
 2039                        editor.update_restoration_data(cx, move |data| {
 2040                            data.scroll_position = (
 2041                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2042                                new_anchor.offset,
 2043                            );
 2044                        });
 2045                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2046                        editor.inline_blame_popover.take();
 2047                    }
 2048                }
 2049                EditorEvent::Edited { .. } => {
 2050                    if !vim_enabled(cx) {
 2051                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2052                        let pop_state = editor
 2053                            .change_list
 2054                            .last()
 2055                            .map(|previous| {
 2056                                previous.len() == selections.len()
 2057                                    && previous.iter().enumerate().all(|(ix, p)| {
 2058                                        p.to_display_point(&map).row()
 2059                                            == selections[ix].head().row()
 2060                                    })
 2061                            })
 2062                            .unwrap_or(false);
 2063                        let new_positions = selections
 2064                            .into_iter()
 2065                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2066                            .collect();
 2067                        editor
 2068                            .change_list
 2069                            .push_to_change_list(pop_state, new_positions);
 2070                    }
 2071                }
 2072                _ => (),
 2073            },
 2074        ));
 2075
 2076        if let Some(dap_store) = editor
 2077            .project
 2078            .as_ref()
 2079            .map(|project| project.read(cx).dap_store())
 2080        {
 2081            let weak_editor = cx.weak_entity();
 2082
 2083            editor
 2084                ._subscriptions
 2085                .push(
 2086                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2087                        let session_entity = cx.entity();
 2088                        weak_editor
 2089                            .update(cx, |editor, cx| {
 2090                                editor._subscriptions.push(
 2091                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2092                                );
 2093                            })
 2094                            .ok();
 2095                    }),
 2096                );
 2097
 2098            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2099                editor
 2100                    ._subscriptions
 2101                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2102            }
 2103        }
 2104
 2105        // skip adding the initial selection to selection history
 2106        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2107        editor.end_selection(window, cx);
 2108        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2109
 2110        editor.scroll_manager.show_scrollbars(window, cx);
 2111        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2112
 2113        if full_mode {
 2114            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2115            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2116
 2117            if editor.git_blame_inline_enabled {
 2118                editor.start_git_blame_inline(false, window, cx);
 2119            }
 2120
 2121            editor.go_to_active_debug_line(window, cx);
 2122
 2123            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2124                if let Some(project) = editor.project.as_ref() {
 2125                    let handle = project.update(cx, |project, cx| {
 2126                        project.register_buffer_with_language_servers(&buffer, cx)
 2127                    });
 2128                    editor
 2129                        .registered_buffers
 2130                        .insert(buffer.read(cx).remote_id(), handle);
 2131                }
 2132            }
 2133
 2134            editor.minimap =
 2135                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2136            editor.pull_diagnostics(None, window, cx);
 2137        }
 2138
 2139        editor.report_editor_event("Editor Opened", None, cx);
 2140        editor
 2141    }
 2142
 2143    pub fn deploy_mouse_context_menu(
 2144        &mut self,
 2145        position: gpui::Point<Pixels>,
 2146        context_menu: Entity<ContextMenu>,
 2147        window: &mut Window,
 2148        cx: &mut Context<Self>,
 2149    ) {
 2150        self.mouse_context_menu = Some(MouseContextMenu::new(
 2151            self,
 2152            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2153            context_menu,
 2154            window,
 2155            cx,
 2156        ));
 2157    }
 2158
 2159    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2160        self.mouse_context_menu
 2161            .as_ref()
 2162            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2163    }
 2164
 2165    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2166        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2167    }
 2168
 2169    fn key_context_internal(
 2170        &self,
 2171        has_active_edit_prediction: bool,
 2172        window: &Window,
 2173        cx: &App,
 2174    ) -> KeyContext {
 2175        let mut key_context = KeyContext::new_with_defaults();
 2176        key_context.add("Editor");
 2177        let mode = match self.mode {
 2178            EditorMode::SingleLine { .. } => "single_line",
 2179            EditorMode::AutoHeight { .. } => "auto_height",
 2180            EditorMode::Minimap { .. } => "minimap",
 2181            EditorMode::Full { .. } => "full",
 2182        };
 2183
 2184        if EditorSettings::jupyter_enabled(cx) {
 2185            key_context.add("jupyter");
 2186        }
 2187
 2188        key_context.set("mode", mode);
 2189        if self.pending_rename.is_some() {
 2190            key_context.add("renaming");
 2191        }
 2192
 2193        match self.context_menu.borrow().as_ref() {
 2194            Some(CodeContextMenu::Completions(_)) => {
 2195                key_context.add("menu");
 2196                key_context.add("showing_completions");
 2197            }
 2198            Some(CodeContextMenu::CodeActions(_)) => {
 2199                key_context.add("menu");
 2200                key_context.add("showing_code_actions")
 2201            }
 2202            None => {}
 2203        }
 2204
 2205        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2206        if !self.focus_handle(cx).contains_focused(window, cx)
 2207            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2208        {
 2209            for addon in self.addons.values() {
 2210                addon.extend_key_context(&mut key_context, cx)
 2211            }
 2212        }
 2213
 2214        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2215            if let Some(extension) = singleton_buffer
 2216                .read(cx)
 2217                .file()
 2218                .and_then(|file| file.path().extension()?.to_str())
 2219            {
 2220                key_context.set("extension", extension.to_string());
 2221            }
 2222        } else {
 2223            key_context.add("multibuffer");
 2224        }
 2225
 2226        if has_active_edit_prediction {
 2227            if self.edit_prediction_in_conflict() {
 2228                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2229            } else {
 2230                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2231                key_context.add("copilot_suggestion");
 2232            }
 2233        }
 2234
 2235        if self.selection_mark_mode {
 2236            key_context.add("selection_mode");
 2237        }
 2238
 2239        key_context
 2240    }
 2241
 2242    fn show_mouse_cursor(&mut self) {
 2243        self.mouse_cursor_hidden = false;
 2244    }
 2245
 2246    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2247        self.mouse_cursor_hidden = match origin {
 2248            HideMouseCursorOrigin::TypingAction => {
 2249                matches!(
 2250                    self.hide_mouse_mode,
 2251                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2252                )
 2253            }
 2254            HideMouseCursorOrigin::MovementAction => {
 2255                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2256            }
 2257        };
 2258    }
 2259
 2260    pub fn edit_prediction_in_conflict(&self) -> bool {
 2261        if !self.show_edit_predictions_in_menu() {
 2262            return false;
 2263        }
 2264
 2265        let showing_completions = self
 2266            .context_menu
 2267            .borrow()
 2268            .as_ref()
 2269            .map_or(false, |context| {
 2270                matches!(context, CodeContextMenu::Completions(_))
 2271            });
 2272
 2273        showing_completions
 2274            || self.edit_prediction_requires_modifier()
 2275            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2276            // bindings to insert tab characters.
 2277            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2278    }
 2279
 2280    pub fn accept_edit_prediction_keybind(
 2281        &self,
 2282        accept_partial: bool,
 2283        window: &Window,
 2284        cx: &App,
 2285    ) -> AcceptEditPredictionBinding {
 2286        let key_context = self.key_context_internal(true, window, cx);
 2287        let in_conflict = self.edit_prediction_in_conflict();
 2288
 2289        let bindings = if accept_partial {
 2290            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2291        } else {
 2292            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2293        };
 2294
 2295        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2296        // just the first one.
 2297        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2298            !in_conflict
 2299                || binding
 2300                    .keystrokes()
 2301                    .first()
 2302                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2303        }))
 2304    }
 2305
 2306    pub fn new_file(
 2307        workspace: &mut Workspace,
 2308        _: &workspace::NewFile,
 2309        window: &mut Window,
 2310        cx: &mut Context<Workspace>,
 2311    ) {
 2312        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2313            "Failed to create buffer",
 2314            window,
 2315            cx,
 2316            |e, _, _| match e.error_code() {
 2317                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2318                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2319                e.error_tag("required").unwrap_or("the latest version")
 2320            )),
 2321                _ => None,
 2322            },
 2323        );
 2324    }
 2325
 2326    pub fn new_in_workspace(
 2327        workspace: &mut Workspace,
 2328        window: &mut Window,
 2329        cx: &mut Context<Workspace>,
 2330    ) -> Task<Result<Entity<Editor>>> {
 2331        let project = workspace.project().clone();
 2332        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2333
 2334        cx.spawn_in(window, async move |workspace, cx| {
 2335            let buffer = create.await?;
 2336            workspace.update_in(cx, |workspace, window, cx| {
 2337                let editor =
 2338                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2339                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2340                editor
 2341            })
 2342        })
 2343    }
 2344
 2345    fn new_file_vertical(
 2346        workspace: &mut Workspace,
 2347        _: &workspace::NewFileSplitVertical,
 2348        window: &mut Window,
 2349        cx: &mut Context<Workspace>,
 2350    ) {
 2351        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2352    }
 2353
 2354    fn new_file_horizontal(
 2355        workspace: &mut Workspace,
 2356        _: &workspace::NewFileSplitHorizontal,
 2357        window: &mut Window,
 2358        cx: &mut Context<Workspace>,
 2359    ) {
 2360        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2361    }
 2362
 2363    fn new_file_in_direction(
 2364        workspace: &mut Workspace,
 2365        direction: SplitDirection,
 2366        window: &mut Window,
 2367        cx: &mut Context<Workspace>,
 2368    ) {
 2369        let project = workspace.project().clone();
 2370        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2371
 2372        cx.spawn_in(window, async move |workspace, cx| {
 2373            let buffer = create.await?;
 2374            workspace.update_in(cx, move |workspace, window, cx| {
 2375                workspace.split_item(
 2376                    direction,
 2377                    Box::new(
 2378                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2379                    ),
 2380                    window,
 2381                    cx,
 2382                )
 2383            })?;
 2384            anyhow::Ok(())
 2385        })
 2386        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2387            match e.error_code() {
 2388                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2389                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2390                e.error_tag("required").unwrap_or("the latest version")
 2391            )),
 2392                _ => None,
 2393            }
 2394        });
 2395    }
 2396
 2397    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2398        self.leader_id
 2399    }
 2400
 2401    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2402        &self.buffer
 2403    }
 2404
 2405    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2406        self.workspace.as_ref()?.0.upgrade()
 2407    }
 2408
 2409    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2410        self.buffer().read(cx).title(cx)
 2411    }
 2412
 2413    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2414        let git_blame_gutter_max_author_length = self
 2415            .render_git_blame_gutter(cx)
 2416            .then(|| {
 2417                if let Some(blame) = self.blame.as_ref() {
 2418                    let max_author_length =
 2419                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2420                    Some(max_author_length)
 2421                } else {
 2422                    None
 2423                }
 2424            })
 2425            .flatten();
 2426
 2427        EditorSnapshot {
 2428            mode: self.mode.clone(),
 2429            show_gutter: self.show_gutter,
 2430            show_line_numbers: self.show_line_numbers,
 2431            show_git_diff_gutter: self.show_git_diff_gutter,
 2432            show_code_actions: self.show_code_actions,
 2433            show_runnables: self.show_runnables,
 2434            show_breakpoints: self.show_breakpoints,
 2435            git_blame_gutter_max_author_length,
 2436            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2437            scroll_anchor: self.scroll_manager.anchor(),
 2438            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2439            placeholder_text: self.placeholder_text.clone(),
 2440            is_focused: self.focus_handle.is_focused(window),
 2441            current_line_highlight: self
 2442                .current_line_highlight
 2443                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2444            gutter_hovered: self.gutter_hovered,
 2445        }
 2446    }
 2447
 2448    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2449        self.buffer.read(cx).language_at(point, cx)
 2450    }
 2451
 2452    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2453        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2454    }
 2455
 2456    pub fn active_excerpt(
 2457        &self,
 2458        cx: &App,
 2459    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2460        self.buffer
 2461            .read(cx)
 2462            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2463    }
 2464
 2465    pub fn mode(&self) -> &EditorMode {
 2466        &self.mode
 2467    }
 2468
 2469    pub fn set_mode(&mut self, mode: EditorMode) {
 2470        self.mode = mode;
 2471    }
 2472
 2473    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2474        self.collaboration_hub.as_deref()
 2475    }
 2476
 2477    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2478        self.collaboration_hub = Some(hub);
 2479    }
 2480
 2481    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2482        self.in_project_search = in_project_search;
 2483    }
 2484
 2485    pub fn set_custom_context_menu(
 2486        &mut self,
 2487        f: impl 'static
 2488        + Fn(
 2489            &mut Self,
 2490            DisplayPoint,
 2491            &mut Window,
 2492            &mut Context<Self>,
 2493        ) -> Option<Entity<ui::ContextMenu>>,
 2494    ) {
 2495        self.custom_context_menu = Some(Box::new(f))
 2496    }
 2497
 2498    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2499        self.completion_provider = provider;
 2500    }
 2501
 2502    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2503        self.semantics_provider.clone()
 2504    }
 2505
 2506    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2507        self.semantics_provider = provider;
 2508    }
 2509
 2510    pub fn set_edit_prediction_provider<T>(
 2511        &mut self,
 2512        provider: Option<Entity<T>>,
 2513        window: &mut Window,
 2514        cx: &mut Context<Self>,
 2515    ) where
 2516        T: EditPredictionProvider,
 2517    {
 2518        self.edit_prediction_provider =
 2519            provider.map(|provider| RegisteredInlineCompletionProvider {
 2520                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2521                    if this.focus_handle.is_focused(window) {
 2522                        this.update_visible_inline_completion(window, cx);
 2523                    }
 2524                }),
 2525                provider: Arc::new(provider),
 2526            });
 2527        self.update_edit_prediction_settings(cx);
 2528        self.refresh_inline_completion(false, false, window, cx);
 2529    }
 2530
 2531    pub fn placeholder_text(&self) -> Option<&str> {
 2532        self.placeholder_text.as_deref()
 2533    }
 2534
 2535    pub fn set_placeholder_text(
 2536        &mut self,
 2537        placeholder_text: impl Into<Arc<str>>,
 2538        cx: &mut Context<Self>,
 2539    ) {
 2540        let placeholder_text = Some(placeholder_text.into());
 2541        if self.placeholder_text != placeholder_text {
 2542            self.placeholder_text = placeholder_text;
 2543            cx.notify();
 2544        }
 2545    }
 2546
 2547    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2548        self.cursor_shape = cursor_shape;
 2549
 2550        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2551        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2552
 2553        cx.notify();
 2554    }
 2555
 2556    pub fn set_current_line_highlight(
 2557        &mut self,
 2558        current_line_highlight: Option<CurrentLineHighlight>,
 2559    ) {
 2560        self.current_line_highlight = current_line_highlight;
 2561    }
 2562
 2563    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2564        self.collapse_matches = collapse_matches;
 2565    }
 2566
 2567    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2568        let buffers = self.buffer.read(cx).all_buffers();
 2569        let Some(project) = self.project.as_ref() else {
 2570            return;
 2571        };
 2572        project.update(cx, |project, cx| {
 2573            for buffer in buffers {
 2574                self.registered_buffers
 2575                    .entry(buffer.read(cx).remote_id())
 2576                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2577            }
 2578        })
 2579    }
 2580
 2581    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2582        if self.collapse_matches {
 2583            return range.start..range.start;
 2584        }
 2585        range.clone()
 2586    }
 2587
 2588    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2589        if self.display_map.read(cx).clip_at_line_ends != clip {
 2590            self.display_map
 2591                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2592        }
 2593    }
 2594
 2595    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2596        self.input_enabled = input_enabled;
 2597    }
 2598
 2599    pub fn set_inline_completions_hidden_for_vim_mode(
 2600        &mut self,
 2601        hidden: bool,
 2602        window: &mut Window,
 2603        cx: &mut Context<Self>,
 2604    ) {
 2605        if hidden != self.inline_completions_hidden_for_vim_mode {
 2606            self.inline_completions_hidden_for_vim_mode = hidden;
 2607            if hidden {
 2608                self.update_visible_inline_completion(window, cx);
 2609            } else {
 2610                self.refresh_inline_completion(true, false, window, cx);
 2611            }
 2612        }
 2613    }
 2614
 2615    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2616        self.menu_inline_completions_policy = value;
 2617    }
 2618
 2619    pub fn set_autoindent(&mut self, autoindent: bool) {
 2620        if autoindent {
 2621            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2622        } else {
 2623            self.autoindent_mode = None;
 2624        }
 2625    }
 2626
 2627    pub fn read_only(&self, cx: &App) -> bool {
 2628        self.read_only || self.buffer.read(cx).read_only()
 2629    }
 2630
 2631    pub fn set_read_only(&mut self, read_only: bool) {
 2632        self.read_only = read_only;
 2633    }
 2634
 2635    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2636        self.use_autoclose = autoclose;
 2637    }
 2638
 2639    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2640        self.use_auto_surround = auto_surround;
 2641    }
 2642
 2643    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2644        self.auto_replace_emoji_shortcode = auto_replace;
 2645    }
 2646
 2647    pub fn toggle_edit_predictions(
 2648        &mut self,
 2649        _: &ToggleEditPrediction,
 2650        window: &mut Window,
 2651        cx: &mut Context<Self>,
 2652    ) {
 2653        if self.show_inline_completions_override.is_some() {
 2654            self.set_show_edit_predictions(None, window, cx);
 2655        } else {
 2656            let show_edit_predictions = !self.edit_predictions_enabled();
 2657            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2658        }
 2659    }
 2660
 2661    pub fn set_show_edit_predictions(
 2662        &mut self,
 2663        show_edit_predictions: Option<bool>,
 2664        window: &mut Window,
 2665        cx: &mut Context<Self>,
 2666    ) {
 2667        self.show_inline_completions_override = show_edit_predictions;
 2668        self.update_edit_prediction_settings(cx);
 2669
 2670        if let Some(false) = show_edit_predictions {
 2671            self.discard_inline_completion(false, cx);
 2672        } else {
 2673            self.refresh_inline_completion(false, true, window, cx);
 2674        }
 2675    }
 2676
 2677    fn inline_completions_disabled_in_scope(
 2678        &self,
 2679        buffer: &Entity<Buffer>,
 2680        buffer_position: language::Anchor,
 2681        cx: &App,
 2682    ) -> bool {
 2683        let snapshot = buffer.read(cx).snapshot();
 2684        let settings = snapshot.settings_at(buffer_position, cx);
 2685
 2686        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2687            return false;
 2688        };
 2689
 2690        scope.override_name().map_or(false, |scope_name| {
 2691            settings
 2692                .edit_predictions_disabled_in
 2693                .iter()
 2694                .any(|s| s == scope_name)
 2695        })
 2696    }
 2697
 2698    pub fn set_use_modal_editing(&mut self, to: bool) {
 2699        self.use_modal_editing = to;
 2700    }
 2701
 2702    pub fn use_modal_editing(&self) -> bool {
 2703        self.use_modal_editing
 2704    }
 2705
 2706    fn selections_did_change(
 2707        &mut self,
 2708        local: bool,
 2709        old_cursor_position: &Anchor,
 2710        should_update_completions: bool,
 2711        window: &mut Window,
 2712        cx: &mut Context<Self>,
 2713    ) {
 2714        window.invalidate_character_coordinates();
 2715
 2716        // Copy selections to primary selection buffer
 2717        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2718        if local {
 2719            let selections = self.selections.all::<usize>(cx);
 2720            let buffer_handle = self.buffer.read(cx).read(cx);
 2721
 2722            let mut text = String::new();
 2723            for (index, selection) in selections.iter().enumerate() {
 2724                let text_for_selection = buffer_handle
 2725                    .text_for_range(selection.start..selection.end)
 2726                    .collect::<String>();
 2727
 2728                text.push_str(&text_for_selection);
 2729                if index != selections.len() - 1 {
 2730                    text.push('\n');
 2731                }
 2732            }
 2733
 2734            if !text.is_empty() {
 2735                cx.write_to_primary(ClipboardItem::new_string(text));
 2736            }
 2737        }
 2738
 2739        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2740            self.buffer.update(cx, |buffer, cx| {
 2741                buffer.set_active_selections(
 2742                    &self.selections.disjoint_anchors(),
 2743                    self.selections.line_mode,
 2744                    self.cursor_shape,
 2745                    cx,
 2746                )
 2747            });
 2748        }
 2749        let display_map = self
 2750            .display_map
 2751            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2752        let buffer = &display_map.buffer_snapshot;
 2753        if self.selections.count() == 1 {
 2754            self.add_selections_state = None;
 2755        }
 2756        self.select_next_state = None;
 2757        self.select_prev_state = None;
 2758        self.select_syntax_node_history.try_clear();
 2759        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2760        self.snippet_stack
 2761            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2762        self.take_rename(false, window, cx);
 2763
 2764        let newest_selection = self.selections.newest_anchor();
 2765        let new_cursor_position = newest_selection.head();
 2766        let selection_start = newest_selection.start;
 2767
 2768        self.push_to_nav_history(
 2769            *old_cursor_position,
 2770            Some(new_cursor_position.to_point(buffer)),
 2771            false,
 2772            cx,
 2773        );
 2774
 2775        if local {
 2776            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2777                if !self.registered_buffers.contains_key(&buffer_id) {
 2778                    if let Some(project) = self.project.as_ref() {
 2779                        project.update(cx, |project, cx| {
 2780                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2781                                return;
 2782                            };
 2783                            self.registered_buffers.insert(
 2784                                buffer_id,
 2785                                project.register_buffer_with_language_servers(&buffer, cx),
 2786                            );
 2787                        })
 2788                    }
 2789                }
 2790            }
 2791
 2792            let mut context_menu = self.context_menu.borrow_mut();
 2793            let completion_menu = match context_menu.as_ref() {
 2794                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2795                Some(CodeContextMenu::CodeActions(_)) => {
 2796                    *context_menu = None;
 2797                    None
 2798                }
 2799                None => None,
 2800            };
 2801            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2802            drop(context_menu);
 2803
 2804            if should_update_completions {
 2805                if let Some(completion_position) = completion_position {
 2806                    let start_offset = selection_start.to_offset(buffer);
 2807                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2808                    let continue_showing = if position_matches {
 2809                        if self.snippet_stack.is_empty() {
 2810                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2811                        } else {
 2812                            // Snippet choices can be shown even when the cursor is in whitespace.
 2813                            // Dismissing the menu when actions like backspace
 2814                            true
 2815                        }
 2816                    } else {
 2817                        false
 2818                    };
 2819
 2820                    if continue_showing {
 2821                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2822                    } else {
 2823                        self.hide_context_menu(window, cx);
 2824                    }
 2825                }
 2826            }
 2827
 2828            hide_hover(self, cx);
 2829
 2830            if old_cursor_position.to_display_point(&display_map).row()
 2831                != new_cursor_position.to_display_point(&display_map).row()
 2832            {
 2833                self.available_code_actions.take();
 2834            }
 2835            self.refresh_code_actions(window, cx);
 2836            self.refresh_document_highlights(cx);
 2837            self.refresh_selected_text_highlights(false, window, cx);
 2838            refresh_matching_bracket_highlights(self, window, cx);
 2839            self.update_visible_inline_completion(window, cx);
 2840            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2841            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2842            self.inline_blame_popover.take();
 2843            if self.git_blame_inline_enabled {
 2844                self.start_inline_blame_timer(window, cx);
 2845            }
 2846        }
 2847
 2848        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2849        cx.emit(EditorEvent::SelectionsChanged { local });
 2850
 2851        let selections = &self.selections.disjoint;
 2852        if selections.len() == 1 {
 2853            cx.emit(SearchEvent::ActiveMatchChanged)
 2854        }
 2855        if local {
 2856            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2857                let inmemory_selections = selections
 2858                    .iter()
 2859                    .map(|s| {
 2860                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2861                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2862                    })
 2863                    .collect();
 2864                self.update_restoration_data(cx, |data| {
 2865                    data.selections = inmemory_selections;
 2866                });
 2867
 2868                if WorkspaceSettings::get(None, cx).restore_on_startup
 2869                    != RestoreOnStartupBehavior::None
 2870                {
 2871                    if let Some(workspace_id) =
 2872                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2873                    {
 2874                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2875                        let selections = selections.clone();
 2876                        let background_executor = cx.background_executor().clone();
 2877                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2878                        self.serialize_selections = cx.background_spawn(async move {
 2879                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2880                    let db_selections = selections
 2881                        .iter()
 2882                        .map(|selection| {
 2883                            (
 2884                                selection.start.to_offset(&snapshot),
 2885                                selection.end.to_offset(&snapshot),
 2886                            )
 2887                        })
 2888                        .collect();
 2889
 2890                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2891                        .await
 2892                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2893                        .log_err();
 2894                });
 2895                    }
 2896                }
 2897            }
 2898        }
 2899
 2900        cx.notify();
 2901    }
 2902
 2903    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2904        use text::ToOffset as _;
 2905        use text::ToPoint as _;
 2906
 2907        if self.mode.is_minimap()
 2908            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2909        {
 2910            return;
 2911        }
 2912
 2913        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2914            return;
 2915        };
 2916
 2917        let snapshot = singleton.read(cx).snapshot();
 2918        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2919            let display_snapshot = display_map.snapshot(cx);
 2920
 2921            display_snapshot
 2922                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2923                .map(|fold| {
 2924                    fold.range.start.text_anchor.to_point(&snapshot)
 2925                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2926                })
 2927                .collect()
 2928        });
 2929        self.update_restoration_data(cx, |data| {
 2930            data.folds = inmemory_folds;
 2931        });
 2932
 2933        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2934            return;
 2935        };
 2936        let background_executor = cx.background_executor().clone();
 2937        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2938        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2939            display_map
 2940                .snapshot(cx)
 2941                .folds_in_range(0..snapshot.len())
 2942                .map(|fold| {
 2943                    (
 2944                        fold.range.start.text_anchor.to_offset(&snapshot),
 2945                        fold.range.end.text_anchor.to_offset(&snapshot),
 2946                    )
 2947                })
 2948                .collect()
 2949        });
 2950        self.serialize_folds = cx.background_spawn(async move {
 2951            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2952            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2953                .await
 2954                .with_context(|| {
 2955                    format!(
 2956                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2957                    )
 2958                })
 2959                .log_err();
 2960        });
 2961    }
 2962
 2963    pub fn sync_selections(
 2964        &mut self,
 2965        other: Entity<Editor>,
 2966        cx: &mut Context<Self>,
 2967    ) -> gpui::Subscription {
 2968        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2969        self.selections.change_with(cx, |selections| {
 2970            selections.select_anchors(other_selections);
 2971        });
 2972
 2973        let other_subscription =
 2974            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2975                EditorEvent::SelectionsChanged { local: true } => {
 2976                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2977                    if other_selections.is_empty() {
 2978                        return;
 2979                    }
 2980                    this.selections.change_with(cx, |selections| {
 2981                        selections.select_anchors(other_selections);
 2982                    });
 2983                }
 2984                _ => {}
 2985            });
 2986
 2987        let this_subscription =
 2988            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2989                EditorEvent::SelectionsChanged { local: true } => {
 2990                    let these_selections = this.selections.disjoint.to_vec();
 2991                    if these_selections.is_empty() {
 2992                        return;
 2993                    }
 2994                    other.update(cx, |other_editor, cx| {
 2995                        other_editor.selections.change_with(cx, |selections| {
 2996                            selections.select_anchors(these_selections);
 2997                        })
 2998                    });
 2999                }
 3000                _ => {}
 3001            });
 3002
 3003        Subscription::join(other_subscription, this_subscription)
 3004    }
 3005
 3006    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3007    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3008    /// effects of selection change occur at the end of the transaction.
 3009    pub fn change_selections<R>(
 3010        &mut self,
 3011        autoscroll: Option<Autoscroll>,
 3012        window: &mut Window,
 3013        cx: &mut Context<Self>,
 3014        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3015    ) -> R {
 3016        self.change_selections_inner(true, autoscroll, window, cx, change)
 3017    }
 3018
 3019    pub(crate) fn change_selections_without_updating_completions<R>(
 3020        &mut self,
 3021        autoscroll: Option<Autoscroll>,
 3022        window: &mut Window,
 3023        cx: &mut Context<Self>,
 3024        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3025    ) -> R {
 3026        self.change_selections_inner(false, autoscroll, window, cx, change)
 3027    }
 3028
 3029    fn change_selections_inner<R>(
 3030        &mut self,
 3031        should_update_completions: bool,
 3032        autoscroll: Option<Autoscroll>,
 3033        window: &mut Window,
 3034        cx: &mut Context<Self>,
 3035        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3036    ) -> R {
 3037        if let Some(state) = &mut self.deferred_selection_effects_state {
 3038            state.autoscroll = autoscroll.or(state.autoscroll);
 3039            state.should_update_completions = should_update_completions;
 3040            let (changed, result) = self.selections.change_with(cx, change);
 3041            state.changed |= changed;
 3042            return result;
 3043        }
 3044        let mut state = DeferredSelectionEffectsState {
 3045            changed: false,
 3046            should_update_completions,
 3047            autoscroll,
 3048            old_cursor_position: self.selections.newest_anchor().head(),
 3049            history_entry: SelectionHistoryEntry {
 3050                selections: self.selections.disjoint_anchors(),
 3051                select_next_state: self.select_next_state.clone(),
 3052                select_prev_state: self.select_prev_state.clone(),
 3053                add_selections_state: self.add_selections_state.clone(),
 3054            },
 3055        };
 3056        let (changed, result) = self.selections.change_with(cx, change);
 3057        state.changed = state.changed || changed;
 3058        if self.defer_selection_effects {
 3059            self.deferred_selection_effects_state = Some(state);
 3060        } else {
 3061            self.apply_selection_effects(state, window, cx);
 3062        }
 3063        result
 3064    }
 3065
 3066    /// Defers the effects of selection change, so that the effects of multiple calls to
 3067    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3068    /// to selection history and the state of popovers based on selection position aren't
 3069    /// erroneously updated.
 3070    pub fn with_selection_effects_deferred<R>(
 3071        &mut self,
 3072        window: &mut Window,
 3073        cx: &mut Context<Self>,
 3074        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3075    ) -> R {
 3076        let already_deferred = self.defer_selection_effects;
 3077        self.defer_selection_effects = true;
 3078        let result = update(self, window, cx);
 3079        if !already_deferred {
 3080            self.defer_selection_effects = false;
 3081            if let Some(state) = self.deferred_selection_effects_state.take() {
 3082                self.apply_selection_effects(state, window, cx);
 3083            }
 3084        }
 3085        result
 3086    }
 3087
 3088    fn apply_selection_effects(
 3089        &mut self,
 3090        state: DeferredSelectionEffectsState,
 3091        window: &mut Window,
 3092        cx: &mut Context<Self>,
 3093    ) {
 3094        if state.changed {
 3095            self.selection_history.push(state.history_entry);
 3096
 3097            if let Some(autoscroll) = state.autoscroll {
 3098                self.request_autoscroll(autoscroll, cx);
 3099            }
 3100
 3101            let old_cursor_position = &state.old_cursor_position;
 3102
 3103            self.selections_did_change(
 3104                true,
 3105                &old_cursor_position,
 3106                state.should_update_completions,
 3107                window,
 3108                cx,
 3109            );
 3110
 3111            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3112                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3113            }
 3114        }
 3115    }
 3116
 3117    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3118    where
 3119        I: IntoIterator<Item = (Range<S>, T)>,
 3120        S: ToOffset,
 3121        T: Into<Arc<str>>,
 3122    {
 3123        if self.read_only(cx) {
 3124            return;
 3125        }
 3126
 3127        self.buffer
 3128            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3129    }
 3130
 3131    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3132    where
 3133        I: IntoIterator<Item = (Range<S>, T)>,
 3134        S: ToOffset,
 3135        T: Into<Arc<str>>,
 3136    {
 3137        if self.read_only(cx) {
 3138            return;
 3139        }
 3140
 3141        self.buffer.update(cx, |buffer, cx| {
 3142            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3143        });
 3144    }
 3145
 3146    pub fn edit_with_block_indent<I, S, T>(
 3147        &mut self,
 3148        edits: I,
 3149        original_indent_columns: Vec<Option<u32>>,
 3150        cx: &mut Context<Self>,
 3151    ) where
 3152        I: IntoIterator<Item = (Range<S>, T)>,
 3153        S: ToOffset,
 3154        T: Into<Arc<str>>,
 3155    {
 3156        if self.read_only(cx) {
 3157            return;
 3158        }
 3159
 3160        self.buffer.update(cx, |buffer, cx| {
 3161            buffer.edit(
 3162                edits,
 3163                Some(AutoindentMode::Block {
 3164                    original_indent_columns,
 3165                }),
 3166                cx,
 3167            )
 3168        });
 3169    }
 3170
 3171    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3172        self.hide_context_menu(window, cx);
 3173
 3174        match phase {
 3175            SelectPhase::Begin {
 3176                position,
 3177                add,
 3178                click_count,
 3179            } => self.begin_selection(position, add, click_count, window, cx),
 3180            SelectPhase::BeginColumnar {
 3181                position,
 3182                goal_column,
 3183                reset,
 3184            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3185            SelectPhase::Extend {
 3186                position,
 3187                click_count,
 3188            } => self.extend_selection(position, click_count, window, cx),
 3189            SelectPhase::Update {
 3190                position,
 3191                goal_column,
 3192                scroll_delta,
 3193            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3194            SelectPhase::End => self.end_selection(window, cx),
 3195        }
 3196    }
 3197
 3198    fn extend_selection(
 3199        &mut self,
 3200        position: DisplayPoint,
 3201        click_count: usize,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3206        let tail = self.selections.newest::<usize>(cx).tail();
 3207        self.begin_selection(position, false, click_count, window, cx);
 3208
 3209        let position = position.to_offset(&display_map, Bias::Left);
 3210        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3211
 3212        let mut pending_selection = self
 3213            .selections
 3214            .pending_anchor()
 3215            .expect("extend_selection not called with pending selection");
 3216        if position >= tail {
 3217            pending_selection.start = tail_anchor;
 3218        } else {
 3219            pending_selection.end = tail_anchor;
 3220            pending_selection.reversed = true;
 3221        }
 3222
 3223        let mut pending_mode = self.selections.pending_mode().unwrap();
 3224        match &mut pending_mode {
 3225            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3226            _ => {}
 3227        }
 3228
 3229        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3230
 3231        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3232            s.set_pending(pending_selection, pending_mode)
 3233        });
 3234    }
 3235
 3236    fn begin_selection(
 3237        &mut self,
 3238        position: DisplayPoint,
 3239        add: bool,
 3240        click_count: usize,
 3241        window: &mut Window,
 3242        cx: &mut Context<Self>,
 3243    ) {
 3244        if !self.focus_handle.is_focused(window) {
 3245            self.last_focused_descendant = None;
 3246            window.focus(&self.focus_handle);
 3247        }
 3248
 3249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3250        let buffer = &display_map.buffer_snapshot;
 3251        let position = display_map.clip_point(position, Bias::Left);
 3252
 3253        let start;
 3254        let end;
 3255        let mode;
 3256        let mut auto_scroll;
 3257        match click_count {
 3258            1 => {
 3259                start = buffer.anchor_before(position.to_point(&display_map));
 3260                end = start;
 3261                mode = SelectMode::Character;
 3262                auto_scroll = true;
 3263            }
 3264            2 => {
 3265                let range = movement::surrounding_word(&display_map, position);
 3266                start = buffer.anchor_before(range.start.to_point(&display_map));
 3267                end = buffer.anchor_before(range.end.to_point(&display_map));
 3268                mode = SelectMode::Word(start..end);
 3269                auto_scroll = true;
 3270            }
 3271            3 => {
 3272                let position = display_map
 3273                    .clip_point(position, Bias::Left)
 3274                    .to_point(&display_map);
 3275                let line_start = display_map.prev_line_boundary(position).0;
 3276                let next_line_start = buffer.clip_point(
 3277                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3278                    Bias::Left,
 3279                );
 3280                start = buffer.anchor_before(line_start);
 3281                end = buffer.anchor_before(next_line_start);
 3282                mode = SelectMode::Line(start..end);
 3283                auto_scroll = true;
 3284            }
 3285            _ => {
 3286                start = buffer.anchor_before(0);
 3287                end = buffer.anchor_before(buffer.len());
 3288                mode = SelectMode::All;
 3289                auto_scroll = false;
 3290            }
 3291        }
 3292        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3293
 3294        let point_to_delete: Option<usize> = {
 3295            let selected_points: Vec<Selection<Point>> =
 3296                self.selections.disjoint_in_range(start..end, cx);
 3297
 3298            if !add || click_count > 1 {
 3299                None
 3300            } else if !selected_points.is_empty() {
 3301                Some(selected_points[0].id)
 3302            } else {
 3303                let clicked_point_already_selected =
 3304                    self.selections.disjoint.iter().find(|selection| {
 3305                        selection.start.to_point(buffer) == start.to_point(buffer)
 3306                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3307                    });
 3308
 3309                clicked_point_already_selected.map(|selection| selection.id)
 3310            }
 3311        };
 3312
 3313        let selections_count = self.selections.count();
 3314
 3315        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3316            if let Some(point_to_delete) = point_to_delete {
 3317                s.delete(point_to_delete);
 3318
 3319                if selections_count == 1 {
 3320                    s.set_pending_anchor_range(start..end, mode);
 3321                }
 3322            } else {
 3323                if !add {
 3324                    s.clear_disjoint();
 3325                }
 3326
 3327                s.set_pending_anchor_range(start..end, mode);
 3328            }
 3329        });
 3330    }
 3331
 3332    fn begin_columnar_selection(
 3333        &mut self,
 3334        position: DisplayPoint,
 3335        goal_column: u32,
 3336        reset: bool,
 3337        window: &mut Window,
 3338        cx: &mut Context<Self>,
 3339    ) {
 3340        if !self.focus_handle.is_focused(window) {
 3341            self.last_focused_descendant = None;
 3342            window.focus(&self.focus_handle);
 3343        }
 3344
 3345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3346
 3347        if reset {
 3348            let pointer_position = display_map
 3349                .buffer_snapshot
 3350                .anchor_before(position.to_point(&display_map));
 3351
 3352            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3353                s.clear_disjoint();
 3354                s.set_pending_anchor_range(
 3355                    pointer_position..pointer_position,
 3356                    SelectMode::Character,
 3357                );
 3358            });
 3359            if position.column() != goal_column {
 3360                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3361            } else {
 3362                self.columnar_display_point = None;
 3363            }
 3364        }
 3365
 3366        let tail = self.selections.newest::<Point>(cx).tail();
 3367        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3368
 3369        if !reset {
 3370            self.columnar_display_point = None;
 3371            self.select_columns(
 3372                tail.to_display_point(&display_map),
 3373                position,
 3374                goal_column,
 3375                &display_map,
 3376                window,
 3377                cx,
 3378            );
 3379        }
 3380    }
 3381
 3382    fn update_selection(
 3383        &mut self,
 3384        position: DisplayPoint,
 3385        goal_column: u32,
 3386        scroll_delta: gpui::Point<f32>,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3391
 3392        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3393            let tail = self
 3394                .columnar_display_point
 3395                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3396            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3397        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3398            let buffer = self.buffer.read(cx).snapshot(cx);
 3399            let head;
 3400            let tail;
 3401            let mode = self.selections.pending_mode().unwrap();
 3402            match &mode {
 3403                SelectMode::Character => {
 3404                    head = position.to_point(&display_map);
 3405                    tail = pending.tail().to_point(&buffer);
 3406                }
 3407                SelectMode::Word(original_range) => {
 3408                    let original_display_range = original_range.start.to_display_point(&display_map)
 3409                        ..original_range.end.to_display_point(&display_map);
 3410                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3411                        ..original_display_range.end.to_point(&display_map);
 3412                    if movement::is_inside_word(&display_map, position)
 3413                        || original_display_range.contains(&position)
 3414                    {
 3415                        let word_range = movement::surrounding_word(&display_map, position);
 3416                        if word_range.start < original_display_range.start {
 3417                            head = word_range.start.to_point(&display_map);
 3418                        } else {
 3419                            head = word_range.end.to_point(&display_map);
 3420                        }
 3421                    } else {
 3422                        head = position.to_point(&display_map);
 3423                    }
 3424
 3425                    if head <= original_buffer_range.start {
 3426                        tail = original_buffer_range.end;
 3427                    } else {
 3428                        tail = original_buffer_range.start;
 3429                    }
 3430                }
 3431                SelectMode::Line(original_range) => {
 3432                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3433
 3434                    let position = display_map
 3435                        .clip_point(position, Bias::Left)
 3436                        .to_point(&display_map);
 3437                    let line_start = display_map.prev_line_boundary(position).0;
 3438                    let next_line_start = buffer.clip_point(
 3439                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3440                        Bias::Left,
 3441                    );
 3442
 3443                    if line_start < original_range.start {
 3444                        head = line_start
 3445                    } else {
 3446                        head = next_line_start
 3447                    }
 3448
 3449                    if head <= original_range.start {
 3450                        tail = original_range.end;
 3451                    } else {
 3452                        tail = original_range.start;
 3453                    }
 3454                }
 3455                SelectMode::All => {
 3456                    return;
 3457                }
 3458            };
 3459
 3460            if head < tail {
 3461                pending.start = buffer.anchor_before(head);
 3462                pending.end = buffer.anchor_before(tail);
 3463                pending.reversed = true;
 3464            } else {
 3465                pending.start = buffer.anchor_before(tail);
 3466                pending.end = buffer.anchor_before(head);
 3467                pending.reversed = false;
 3468            }
 3469
 3470            self.change_selections(None, window, cx, |s| {
 3471                s.set_pending(pending, mode);
 3472            });
 3473        } else {
 3474            log::error!("update_selection dispatched with no pending selection");
 3475            return;
 3476        }
 3477
 3478        self.apply_scroll_delta(scroll_delta, window, cx);
 3479        cx.notify();
 3480    }
 3481
 3482    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3483        self.columnar_selection_tail.take();
 3484        if self.selections.pending_anchor().is_some() {
 3485            let selections = self.selections.all::<usize>(cx);
 3486            self.change_selections(None, window, cx, |s| {
 3487                s.select(selections);
 3488                s.clear_pending();
 3489            });
 3490        }
 3491    }
 3492
 3493    fn select_columns(
 3494        &mut self,
 3495        tail: DisplayPoint,
 3496        head: DisplayPoint,
 3497        goal_column: u32,
 3498        display_map: &DisplaySnapshot,
 3499        window: &mut Window,
 3500        cx: &mut Context<Self>,
 3501    ) {
 3502        let start_row = cmp::min(tail.row(), head.row());
 3503        let end_row = cmp::max(tail.row(), head.row());
 3504        let start_column = cmp::min(tail.column(), goal_column);
 3505        let end_column = cmp::max(tail.column(), goal_column);
 3506        let reversed = start_column < tail.column();
 3507
 3508        let selection_ranges = (start_row.0..=end_row.0)
 3509            .map(DisplayRow)
 3510            .filter_map(|row| {
 3511                if !display_map.is_block_line(row) {
 3512                    let start = display_map
 3513                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3514                        .to_point(display_map);
 3515                    let end = display_map
 3516                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3517                        .to_point(display_map);
 3518                    if reversed {
 3519                        Some(end..start)
 3520                    } else {
 3521                        Some(start..end)
 3522                    }
 3523                } else {
 3524                    None
 3525                }
 3526            })
 3527            .collect::<Vec<_>>();
 3528
 3529        let mut non_empty_ranges = selection_ranges
 3530            .iter()
 3531            .filter(|selection_range| selection_range.start != selection_range.end)
 3532            .peekable();
 3533
 3534        let ranges = if non_empty_ranges.peek().is_some() {
 3535            non_empty_ranges.cloned().collect()
 3536        } else {
 3537            selection_ranges
 3538        };
 3539
 3540        self.change_selections(None, window, cx, |s| {
 3541            s.select_ranges(ranges);
 3542        });
 3543        cx.notify();
 3544    }
 3545
 3546    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3547        self.selections
 3548            .all_adjusted(cx)
 3549            .iter()
 3550            .any(|selection| !selection.is_empty())
 3551    }
 3552
 3553    pub fn has_pending_nonempty_selection(&self) -> bool {
 3554        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3555            Some(Selection { start, end, .. }) => start != end,
 3556            None => false,
 3557        };
 3558
 3559        pending_nonempty_selection
 3560            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3561    }
 3562
 3563    pub fn has_pending_selection(&self) -> bool {
 3564        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3565    }
 3566
 3567    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3568        self.selection_mark_mode = false;
 3569        self.selection_drag_state = SelectionDragState::None;
 3570
 3571        if self.clear_expanded_diff_hunks(cx) {
 3572            cx.notify();
 3573            return;
 3574        }
 3575        if self.dismiss_menus_and_popups(true, window, cx) {
 3576            return;
 3577        }
 3578
 3579        if self.mode.is_full()
 3580            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3581        {
 3582            return;
 3583        }
 3584
 3585        cx.propagate();
 3586    }
 3587
 3588    pub fn dismiss_menus_and_popups(
 3589        &mut self,
 3590        is_user_requested: bool,
 3591        window: &mut Window,
 3592        cx: &mut Context<Self>,
 3593    ) -> bool {
 3594        if self.take_rename(false, window, cx).is_some() {
 3595            return true;
 3596        }
 3597
 3598        if hide_hover(self, cx) {
 3599            return true;
 3600        }
 3601
 3602        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3603            return true;
 3604        }
 3605
 3606        if self.hide_context_menu(window, cx).is_some() {
 3607            return true;
 3608        }
 3609
 3610        if self.mouse_context_menu.take().is_some() {
 3611            return true;
 3612        }
 3613
 3614        if is_user_requested && self.discard_inline_completion(true, cx) {
 3615            return true;
 3616        }
 3617
 3618        if self.snippet_stack.pop().is_some() {
 3619            return true;
 3620        }
 3621
 3622        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3623            self.dismiss_diagnostics(cx);
 3624            return true;
 3625        }
 3626
 3627        false
 3628    }
 3629
 3630    fn linked_editing_ranges_for(
 3631        &self,
 3632        selection: Range<text::Anchor>,
 3633        cx: &App,
 3634    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3635        if self.linked_edit_ranges.is_empty() {
 3636            return None;
 3637        }
 3638        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3639            selection.end.buffer_id.and_then(|end_buffer_id| {
 3640                if selection.start.buffer_id != Some(end_buffer_id) {
 3641                    return None;
 3642                }
 3643                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3644                let snapshot = buffer.read(cx).snapshot();
 3645                self.linked_edit_ranges
 3646                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3647                    .map(|ranges| (ranges, snapshot, buffer))
 3648            })?;
 3649        use text::ToOffset as TO;
 3650        // find offset from the start of current range to current cursor position
 3651        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3652
 3653        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3654        let start_difference = start_offset - start_byte_offset;
 3655        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3656        let end_difference = end_offset - start_byte_offset;
 3657        // Current range has associated linked ranges.
 3658        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3659        for range in linked_ranges.iter() {
 3660            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3661            let end_offset = start_offset + end_difference;
 3662            let start_offset = start_offset + start_difference;
 3663            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3664                continue;
 3665            }
 3666            if self.selections.disjoint_anchor_ranges().any(|s| {
 3667                if s.start.buffer_id != selection.start.buffer_id
 3668                    || s.end.buffer_id != selection.end.buffer_id
 3669                {
 3670                    return false;
 3671                }
 3672                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3673                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3674            }) {
 3675                continue;
 3676            }
 3677            let start = buffer_snapshot.anchor_after(start_offset);
 3678            let end = buffer_snapshot.anchor_after(end_offset);
 3679            linked_edits
 3680                .entry(buffer.clone())
 3681                .or_default()
 3682                .push(start..end);
 3683        }
 3684        Some(linked_edits)
 3685    }
 3686
 3687    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3688        let text: Arc<str> = text.into();
 3689
 3690        if self.read_only(cx) {
 3691            return;
 3692        }
 3693
 3694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3695
 3696        let selections = self.selections.all_adjusted(cx);
 3697        let mut bracket_inserted = false;
 3698        let mut edits = Vec::new();
 3699        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3700        let mut new_selections = Vec::with_capacity(selections.len());
 3701        let mut new_autoclose_regions = Vec::new();
 3702        let snapshot = self.buffer.read(cx).read(cx);
 3703        let mut clear_linked_edit_ranges = false;
 3704
 3705        for (selection, autoclose_region) in
 3706            self.selections_with_autoclose_regions(selections, &snapshot)
 3707        {
 3708            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3709                // Determine if the inserted text matches the opening or closing
 3710                // bracket of any of this language's bracket pairs.
 3711                let mut bracket_pair = None;
 3712                let mut is_bracket_pair_start = false;
 3713                let mut is_bracket_pair_end = false;
 3714                if !text.is_empty() {
 3715                    let mut bracket_pair_matching_end = None;
 3716                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3717                    //  and they are removing the character that triggered IME popup.
 3718                    for (pair, enabled) in scope.brackets() {
 3719                        if !pair.close && !pair.surround {
 3720                            continue;
 3721                        }
 3722
 3723                        if enabled && pair.start.ends_with(text.as_ref()) {
 3724                            let prefix_len = pair.start.len() - text.len();
 3725                            let preceding_text_matches_prefix = prefix_len == 0
 3726                                || (selection.start.column >= (prefix_len as u32)
 3727                                    && snapshot.contains_str_at(
 3728                                        Point::new(
 3729                                            selection.start.row,
 3730                                            selection.start.column - (prefix_len as u32),
 3731                                        ),
 3732                                        &pair.start[..prefix_len],
 3733                                    ));
 3734                            if preceding_text_matches_prefix {
 3735                                bracket_pair = Some(pair.clone());
 3736                                is_bracket_pair_start = true;
 3737                                break;
 3738                            }
 3739                        }
 3740                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3741                        {
 3742                            // take first bracket pair matching end, but don't break in case a later bracket
 3743                            // pair matches start
 3744                            bracket_pair_matching_end = Some(pair.clone());
 3745                        }
 3746                    }
 3747                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3748                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3749                        is_bracket_pair_end = true;
 3750                    }
 3751                }
 3752
 3753                if let Some(bracket_pair) = bracket_pair {
 3754                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3755                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3756                    let auto_surround =
 3757                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3758                    if selection.is_empty() {
 3759                        if is_bracket_pair_start {
 3760                            // If the inserted text is a suffix of an opening bracket and the
 3761                            // selection is preceded by the rest of the opening bracket, then
 3762                            // insert the closing bracket.
 3763                            let following_text_allows_autoclose = snapshot
 3764                                .chars_at(selection.start)
 3765                                .next()
 3766                                .map_or(true, |c| scope.should_autoclose_before(c));
 3767
 3768                            let preceding_text_allows_autoclose = selection.start.column == 0
 3769                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3770                                    true,
 3771                                    |c| {
 3772                                        bracket_pair.start != bracket_pair.end
 3773                                            || !snapshot
 3774                                                .char_classifier_at(selection.start)
 3775                                                .is_word(c)
 3776                                    },
 3777                                );
 3778
 3779                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3780                                && bracket_pair.start.len() == 1
 3781                            {
 3782                                let target = bracket_pair.start.chars().next().unwrap();
 3783                                let current_line_count = snapshot
 3784                                    .reversed_chars_at(selection.start)
 3785                                    .take_while(|&c| c != '\n')
 3786                                    .filter(|&c| c == target)
 3787                                    .count();
 3788                                current_line_count % 2 == 1
 3789                            } else {
 3790                                false
 3791                            };
 3792
 3793                            if autoclose
 3794                                && bracket_pair.close
 3795                                && following_text_allows_autoclose
 3796                                && preceding_text_allows_autoclose
 3797                                && !is_closing_quote
 3798                            {
 3799                                let anchor = snapshot.anchor_before(selection.end);
 3800                                new_selections.push((selection.map(|_| anchor), text.len()));
 3801                                new_autoclose_regions.push((
 3802                                    anchor,
 3803                                    text.len(),
 3804                                    selection.id,
 3805                                    bracket_pair.clone(),
 3806                                ));
 3807                                edits.push((
 3808                                    selection.range(),
 3809                                    format!("{}{}", text, bracket_pair.end).into(),
 3810                                ));
 3811                                bracket_inserted = true;
 3812                                continue;
 3813                            }
 3814                        }
 3815
 3816                        if let Some(region) = autoclose_region {
 3817                            // If the selection is followed by an auto-inserted closing bracket,
 3818                            // then don't insert that closing bracket again; just move the selection
 3819                            // past the closing bracket.
 3820                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3821                                && text.as_ref() == region.pair.end.as_str();
 3822                            if should_skip {
 3823                                let anchor = snapshot.anchor_after(selection.end);
 3824                                new_selections
 3825                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3826                                continue;
 3827                            }
 3828                        }
 3829
 3830                        let always_treat_brackets_as_autoclosed = snapshot
 3831                            .language_settings_at(selection.start, cx)
 3832                            .always_treat_brackets_as_autoclosed;
 3833                        if always_treat_brackets_as_autoclosed
 3834                            && is_bracket_pair_end
 3835                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3836                        {
 3837                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3838                            // and the inserted text is a closing bracket and the selection is followed
 3839                            // by the closing bracket then move the selection past the closing bracket.
 3840                            let anchor = snapshot.anchor_after(selection.end);
 3841                            new_selections.push((selection.map(|_| anchor), text.len()));
 3842                            continue;
 3843                        }
 3844                    }
 3845                    // If an opening bracket is 1 character long and is typed while
 3846                    // text is selected, then surround that text with the bracket pair.
 3847                    else if auto_surround
 3848                        && bracket_pair.surround
 3849                        && is_bracket_pair_start
 3850                        && bracket_pair.start.chars().count() == 1
 3851                    {
 3852                        edits.push((selection.start..selection.start, text.clone()));
 3853                        edits.push((
 3854                            selection.end..selection.end,
 3855                            bracket_pair.end.as_str().into(),
 3856                        ));
 3857                        bracket_inserted = true;
 3858                        new_selections.push((
 3859                            Selection {
 3860                                id: selection.id,
 3861                                start: snapshot.anchor_after(selection.start),
 3862                                end: snapshot.anchor_before(selection.end),
 3863                                reversed: selection.reversed,
 3864                                goal: selection.goal,
 3865                            },
 3866                            0,
 3867                        ));
 3868                        continue;
 3869                    }
 3870                }
 3871            }
 3872
 3873            if self.auto_replace_emoji_shortcode
 3874                && selection.is_empty()
 3875                && text.as_ref().ends_with(':')
 3876            {
 3877                if let Some(possible_emoji_short_code) =
 3878                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3879                {
 3880                    if !possible_emoji_short_code.is_empty() {
 3881                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3882                            let emoji_shortcode_start = Point::new(
 3883                                selection.start.row,
 3884                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3885                            );
 3886
 3887                            // Remove shortcode from buffer
 3888                            edits.push((
 3889                                emoji_shortcode_start..selection.start,
 3890                                "".to_string().into(),
 3891                            ));
 3892                            new_selections.push((
 3893                                Selection {
 3894                                    id: selection.id,
 3895                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3896                                    end: snapshot.anchor_before(selection.start),
 3897                                    reversed: selection.reversed,
 3898                                    goal: selection.goal,
 3899                                },
 3900                                0,
 3901                            ));
 3902
 3903                            // Insert emoji
 3904                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3905                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3906                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3907
 3908                            continue;
 3909                        }
 3910                    }
 3911                }
 3912            }
 3913
 3914            // If not handling any auto-close operation, then just replace the selected
 3915            // text with the given input and move the selection to the end of the
 3916            // newly inserted text.
 3917            let anchor = snapshot.anchor_after(selection.end);
 3918            if !self.linked_edit_ranges.is_empty() {
 3919                let start_anchor = snapshot.anchor_before(selection.start);
 3920
 3921                let is_word_char = text.chars().next().map_or(true, |char| {
 3922                    let classifier = snapshot
 3923                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3924                        .ignore_punctuation(true);
 3925                    classifier.is_word(char)
 3926                });
 3927
 3928                if is_word_char {
 3929                    if let Some(ranges) = self
 3930                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3931                    {
 3932                        for (buffer, edits) in ranges {
 3933                            linked_edits
 3934                                .entry(buffer.clone())
 3935                                .or_default()
 3936                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3937                        }
 3938                    }
 3939                } else {
 3940                    clear_linked_edit_ranges = true;
 3941                }
 3942            }
 3943
 3944            new_selections.push((selection.map(|_| anchor), 0));
 3945            edits.push((selection.start..selection.end, text.clone()));
 3946        }
 3947
 3948        drop(snapshot);
 3949
 3950        self.transact(window, cx, |this, window, cx| {
 3951            if clear_linked_edit_ranges {
 3952                this.linked_edit_ranges.clear();
 3953            }
 3954            let initial_buffer_versions =
 3955                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3956
 3957            this.buffer.update(cx, |buffer, cx| {
 3958                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3959            });
 3960            for (buffer, edits) in linked_edits {
 3961                buffer.update(cx, |buffer, cx| {
 3962                    let snapshot = buffer.snapshot();
 3963                    let edits = edits
 3964                        .into_iter()
 3965                        .map(|(range, text)| {
 3966                            use text::ToPoint as TP;
 3967                            let end_point = TP::to_point(&range.end, &snapshot);
 3968                            let start_point = TP::to_point(&range.start, &snapshot);
 3969                            (start_point..end_point, text)
 3970                        })
 3971                        .sorted_by_key(|(range, _)| range.start);
 3972                    buffer.edit(edits, None, cx);
 3973                })
 3974            }
 3975            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3976            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3977            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3978            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3979                .zip(new_selection_deltas)
 3980                .map(|(selection, delta)| Selection {
 3981                    id: selection.id,
 3982                    start: selection.start + delta,
 3983                    end: selection.end + delta,
 3984                    reversed: selection.reversed,
 3985                    goal: SelectionGoal::None,
 3986                })
 3987                .collect::<Vec<_>>();
 3988
 3989            let mut i = 0;
 3990            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3991                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3992                let start = map.buffer_snapshot.anchor_before(position);
 3993                let end = map.buffer_snapshot.anchor_after(position);
 3994                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3995                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3996                        Ordering::Less => i += 1,
 3997                        Ordering::Greater => break,
 3998                        Ordering::Equal => {
 3999                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4000                                Ordering::Less => i += 1,
 4001                                Ordering::Equal => break,
 4002                                Ordering::Greater => break,
 4003                            }
 4004                        }
 4005                    }
 4006                }
 4007                this.autoclose_regions.insert(
 4008                    i,
 4009                    AutocloseRegion {
 4010                        selection_id,
 4011                        range: start..end,
 4012                        pair,
 4013                    },
 4014                );
 4015            }
 4016
 4017            let had_active_inline_completion = this.has_active_inline_completion();
 4018            this.change_selections_without_updating_completions(
 4019                Some(Autoscroll::fit()),
 4020                window,
 4021                cx,
 4022                |s| s.select(new_selections),
 4023            );
 4024
 4025            if !bracket_inserted {
 4026                if let Some(on_type_format_task) =
 4027                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4028                {
 4029                    on_type_format_task.detach_and_log_err(cx);
 4030                }
 4031            }
 4032
 4033            let editor_settings = EditorSettings::get_global(cx);
 4034            if bracket_inserted
 4035                && (editor_settings.auto_signature_help
 4036                    || editor_settings.show_signature_help_after_edits)
 4037            {
 4038                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4039            }
 4040
 4041            let trigger_in_words =
 4042                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4043            if this.hard_wrap.is_some() {
 4044                let latest: Range<Point> = this.selections.newest(cx).range();
 4045                if latest.is_empty()
 4046                    && this
 4047                        .buffer()
 4048                        .read(cx)
 4049                        .snapshot(cx)
 4050                        .line_len(MultiBufferRow(latest.start.row))
 4051                        == latest.start.column
 4052                {
 4053                    this.rewrap_impl(
 4054                        RewrapOptions {
 4055                            override_language_settings: true,
 4056                            preserve_existing_whitespace: true,
 4057                        },
 4058                        cx,
 4059                    )
 4060                }
 4061            }
 4062            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4063            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4064            this.refresh_inline_completion(true, false, window, cx);
 4065            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4066        });
 4067    }
 4068
 4069    fn find_possible_emoji_shortcode_at_position(
 4070        snapshot: &MultiBufferSnapshot,
 4071        position: Point,
 4072    ) -> Option<String> {
 4073        let mut chars = Vec::new();
 4074        let mut found_colon = false;
 4075        for char in snapshot.reversed_chars_at(position).take(100) {
 4076            // Found a possible emoji shortcode in the middle of the buffer
 4077            if found_colon {
 4078                if char.is_whitespace() {
 4079                    chars.reverse();
 4080                    return Some(chars.iter().collect());
 4081                }
 4082                // If the previous character is not a whitespace, we are in the middle of a word
 4083                // and we only want to complete the shortcode if the word is made up of other emojis
 4084                let mut containing_word = String::new();
 4085                for ch in snapshot
 4086                    .reversed_chars_at(position)
 4087                    .skip(chars.len() + 1)
 4088                    .take(100)
 4089                {
 4090                    if ch.is_whitespace() {
 4091                        break;
 4092                    }
 4093                    containing_word.push(ch);
 4094                }
 4095                let containing_word = containing_word.chars().rev().collect::<String>();
 4096                if util::word_consists_of_emojis(containing_word.as_str()) {
 4097                    chars.reverse();
 4098                    return Some(chars.iter().collect());
 4099                }
 4100            }
 4101
 4102            if char.is_whitespace() || !char.is_ascii() {
 4103                return None;
 4104            }
 4105            if char == ':' {
 4106                found_colon = true;
 4107            } else {
 4108                chars.push(char);
 4109            }
 4110        }
 4111        // Found a possible emoji shortcode at the beginning of the buffer
 4112        chars.reverse();
 4113        Some(chars.iter().collect())
 4114    }
 4115
 4116    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4118        self.transact(window, cx, |this, window, cx| {
 4119            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4120                let selections = this.selections.all::<usize>(cx);
 4121                let multi_buffer = this.buffer.read(cx);
 4122                let buffer = multi_buffer.snapshot(cx);
 4123                selections
 4124                    .iter()
 4125                    .map(|selection| {
 4126                        let start_point = selection.start.to_point(&buffer);
 4127                        let mut existing_indent =
 4128                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4129                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4130                        let start = selection.start;
 4131                        let end = selection.end;
 4132                        let selection_is_empty = start == end;
 4133                        let language_scope = buffer.language_scope_at(start);
 4134                        let (
 4135                            comment_delimiter,
 4136                            doc_delimiter,
 4137                            insert_extra_newline,
 4138                            indent_on_newline,
 4139                            indent_on_extra_newline,
 4140                        ) = if let Some(language) = &language_scope {
 4141                            let mut insert_extra_newline =
 4142                                insert_extra_newline_brackets(&buffer, start..end, language)
 4143                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4144
 4145                            // Comment extension on newline is allowed only for cursor selections
 4146                            let comment_delimiter = maybe!({
 4147                                if !selection_is_empty {
 4148                                    return None;
 4149                                }
 4150
 4151                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4152                                    return None;
 4153                                }
 4154
 4155                                let delimiters = language.line_comment_prefixes();
 4156                                let max_len_of_delimiter =
 4157                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4158                                let (snapshot, range) =
 4159                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4160
 4161                                let num_of_whitespaces = snapshot
 4162                                    .chars_for_range(range.clone())
 4163                                    .take_while(|c| c.is_whitespace())
 4164                                    .count();
 4165                                let comment_candidate = snapshot
 4166                                    .chars_for_range(range)
 4167                                    .skip(num_of_whitespaces)
 4168                                    .take(max_len_of_delimiter)
 4169                                    .collect::<String>();
 4170                                let (delimiter, trimmed_len) = delimiters
 4171                                    .iter()
 4172                                    .filter_map(|delimiter| {
 4173                                        let prefix = delimiter.trim_end();
 4174                                        if comment_candidate.starts_with(prefix) {
 4175                                            Some((delimiter, prefix.len()))
 4176                                        } else {
 4177                                            None
 4178                                        }
 4179                                    })
 4180                                    .max_by_key(|(_, len)| *len)?;
 4181
 4182                                let cursor_is_placed_after_comment_marker =
 4183                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4184                                if cursor_is_placed_after_comment_marker {
 4185                                    Some(delimiter.clone())
 4186                                } else {
 4187                                    None
 4188                                }
 4189                            });
 4190
 4191                            let mut indent_on_newline = IndentSize::spaces(0);
 4192                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4193
 4194                            let doc_delimiter = maybe!({
 4195                                if !selection_is_empty {
 4196                                    return None;
 4197                                }
 4198
 4199                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4200                                    return None;
 4201                                }
 4202
 4203                                let DocumentationConfig {
 4204                                    start: start_tag,
 4205                                    end: end_tag,
 4206                                    prefix: delimiter,
 4207                                    tab_size: len,
 4208                                } = language.documentation()?;
 4209
 4210                                let is_within_block_comment = buffer
 4211                                    .language_scope_at(start_point)
 4212                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4213                                if !is_within_block_comment {
 4214                                    return None;
 4215                                }
 4216
 4217                                let (snapshot, range) =
 4218                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4219
 4220                                let num_of_whitespaces = snapshot
 4221                                    .chars_for_range(range.clone())
 4222                                    .take_while(|c| c.is_whitespace())
 4223                                    .count();
 4224
 4225                                // 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.
 4226                                let column = start_point.column;
 4227                                let cursor_is_after_start_tag = {
 4228                                    let start_tag_len = start_tag.len();
 4229                                    let start_tag_line = snapshot
 4230                                        .chars_for_range(range.clone())
 4231                                        .skip(num_of_whitespaces)
 4232                                        .take(start_tag_len)
 4233                                        .collect::<String>();
 4234                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4235                                        num_of_whitespaces + start_tag_len <= column as usize
 4236                                    } else {
 4237                                        false
 4238                                    }
 4239                                };
 4240
 4241                                let cursor_is_after_delimiter = {
 4242                                    let delimiter_trim = delimiter.trim_end();
 4243                                    let delimiter_line = snapshot
 4244                                        .chars_for_range(range.clone())
 4245                                        .skip(num_of_whitespaces)
 4246                                        .take(delimiter_trim.len())
 4247                                        .collect::<String>();
 4248                                    if delimiter_line.starts_with(delimiter_trim) {
 4249                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4250                                    } else {
 4251                                        false
 4252                                    }
 4253                                };
 4254
 4255                                let cursor_is_before_end_tag_if_exists = {
 4256                                    let mut char_position = 0u32;
 4257                                    let mut end_tag_offset = None;
 4258
 4259                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4260                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4261                                            let chars_before_match =
 4262                                                chunk[..byte_pos].chars().count() as u32;
 4263                                            end_tag_offset =
 4264                                                Some(char_position + chars_before_match);
 4265                                            break 'outer;
 4266                                        }
 4267                                        char_position += chunk.chars().count() as u32;
 4268                                    }
 4269
 4270                                    if let Some(end_tag_offset) = end_tag_offset {
 4271                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4272                                        if cursor_is_after_start_tag {
 4273                                            if cursor_is_before_end_tag {
 4274                                                insert_extra_newline = true;
 4275                                            }
 4276                                            let cursor_is_at_start_of_end_tag =
 4277                                                column == end_tag_offset;
 4278                                            if cursor_is_at_start_of_end_tag {
 4279                                                indent_on_extra_newline.len = (*len).into();
 4280                                            }
 4281                                        }
 4282                                        cursor_is_before_end_tag
 4283                                    } else {
 4284                                        true
 4285                                    }
 4286                                };
 4287
 4288                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4289                                    && cursor_is_before_end_tag_if_exists
 4290                                {
 4291                                    if cursor_is_after_start_tag {
 4292                                        indent_on_newline.len = (*len).into();
 4293                                    }
 4294                                    Some(delimiter.clone())
 4295                                } else {
 4296                                    None
 4297                                }
 4298                            });
 4299
 4300                            (
 4301                                comment_delimiter,
 4302                                doc_delimiter,
 4303                                insert_extra_newline,
 4304                                indent_on_newline,
 4305                                indent_on_extra_newline,
 4306                            )
 4307                        } else {
 4308                            (
 4309                                None,
 4310                                None,
 4311                                false,
 4312                                IndentSize::default(),
 4313                                IndentSize::default(),
 4314                            )
 4315                        };
 4316
 4317                        let prevent_auto_indent = doc_delimiter.is_some();
 4318                        let delimiter = comment_delimiter.or(doc_delimiter);
 4319
 4320                        let capacity_for_delimiter =
 4321                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4322                        let mut new_text = String::with_capacity(
 4323                            1 + capacity_for_delimiter
 4324                                + existing_indent.len as usize
 4325                                + indent_on_newline.len as usize
 4326                                + indent_on_extra_newline.len as usize,
 4327                        );
 4328                        new_text.push('\n');
 4329                        new_text.extend(existing_indent.chars());
 4330                        new_text.extend(indent_on_newline.chars());
 4331
 4332                        if let Some(delimiter) = &delimiter {
 4333                            new_text.push_str(delimiter);
 4334                        }
 4335
 4336                        if insert_extra_newline {
 4337                            new_text.push('\n');
 4338                            new_text.extend(existing_indent.chars());
 4339                            new_text.extend(indent_on_extra_newline.chars());
 4340                        }
 4341
 4342                        let anchor = buffer.anchor_after(end);
 4343                        let new_selection = selection.map(|_| anchor);
 4344                        (
 4345                            ((start..end, new_text), prevent_auto_indent),
 4346                            (insert_extra_newline, new_selection),
 4347                        )
 4348                    })
 4349                    .unzip()
 4350            };
 4351
 4352            let mut auto_indent_edits = Vec::new();
 4353            let mut edits = Vec::new();
 4354            for (edit, prevent_auto_indent) in edits_with_flags {
 4355                if prevent_auto_indent {
 4356                    edits.push(edit);
 4357                } else {
 4358                    auto_indent_edits.push(edit);
 4359                }
 4360            }
 4361            if !edits.is_empty() {
 4362                this.edit(edits, cx);
 4363            }
 4364            if !auto_indent_edits.is_empty() {
 4365                this.edit_with_autoindent(auto_indent_edits, cx);
 4366            }
 4367
 4368            let buffer = this.buffer.read(cx).snapshot(cx);
 4369            let new_selections = selection_info
 4370                .into_iter()
 4371                .map(|(extra_newline_inserted, new_selection)| {
 4372                    let mut cursor = new_selection.end.to_point(&buffer);
 4373                    if extra_newline_inserted {
 4374                        cursor.row -= 1;
 4375                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4376                    }
 4377                    new_selection.map(|_| cursor)
 4378                })
 4379                .collect();
 4380
 4381            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4382                s.select(new_selections)
 4383            });
 4384            this.refresh_inline_completion(true, false, window, cx);
 4385        });
 4386    }
 4387
 4388    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4389        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4390
 4391        let buffer = self.buffer.read(cx);
 4392        let snapshot = buffer.snapshot(cx);
 4393
 4394        let mut edits = Vec::new();
 4395        let mut rows = Vec::new();
 4396
 4397        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4398            let cursor = selection.head();
 4399            let row = cursor.row;
 4400
 4401            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4402
 4403            let newline = "\n".to_string();
 4404            edits.push((start_of_line..start_of_line, newline));
 4405
 4406            rows.push(row + rows_inserted as u32);
 4407        }
 4408
 4409        self.transact(window, cx, |editor, window, cx| {
 4410            editor.edit(edits, cx);
 4411
 4412            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4413                let mut index = 0;
 4414                s.move_cursors_with(|map, _, _| {
 4415                    let row = rows[index];
 4416                    index += 1;
 4417
 4418                    let point = Point::new(row, 0);
 4419                    let boundary = map.next_line_boundary(point).1;
 4420                    let clipped = map.clip_point(boundary, Bias::Left);
 4421
 4422                    (clipped, SelectionGoal::None)
 4423                });
 4424            });
 4425
 4426            let mut indent_edits = Vec::new();
 4427            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4428            for row in rows {
 4429                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4430                for (row, indent) in indents {
 4431                    if indent.len == 0 {
 4432                        continue;
 4433                    }
 4434
 4435                    let text = match indent.kind {
 4436                        IndentKind::Space => " ".repeat(indent.len as usize),
 4437                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4438                    };
 4439                    let point = Point::new(row.0, 0);
 4440                    indent_edits.push((point..point, text));
 4441                }
 4442            }
 4443            editor.edit(indent_edits, cx);
 4444        });
 4445    }
 4446
 4447    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4448        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4449
 4450        let buffer = self.buffer.read(cx);
 4451        let snapshot = buffer.snapshot(cx);
 4452
 4453        let mut edits = Vec::new();
 4454        let mut rows = Vec::new();
 4455        let mut rows_inserted = 0;
 4456
 4457        for selection in self.selections.all_adjusted(cx) {
 4458            let cursor = selection.head();
 4459            let row = cursor.row;
 4460
 4461            let point = Point::new(row + 1, 0);
 4462            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4463
 4464            let newline = "\n".to_string();
 4465            edits.push((start_of_line..start_of_line, newline));
 4466
 4467            rows_inserted += 1;
 4468            rows.push(row + rows_inserted);
 4469        }
 4470
 4471        self.transact(window, cx, |editor, window, cx| {
 4472            editor.edit(edits, cx);
 4473
 4474            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4475                let mut index = 0;
 4476                s.move_cursors_with(|map, _, _| {
 4477                    let row = rows[index];
 4478                    index += 1;
 4479
 4480                    let point = Point::new(row, 0);
 4481                    let boundary = map.next_line_boundary(point).1;
 4482                    let clipped = map.clip_point(boundary, Bias::Left);
 4483
 4484                    (clipped, SelectionGoal::None)
 4485                });
 4486            });
 4487
 4488            let mut indent_edits = Vec::new();
 4489            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4490            for row in rows {
 4491                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4492                for (row, indent) in indents {
 4493                    if indent.len == 0 {
 4494                        continue;
 4495                    }
 4496
 4497                    let text = match indent.kind {
 4498                        IndentKind::Space => " ".repeat(indent.len as usize),
 4499                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4500                    };
 4501                    let point = Point::new(row.0, 0);
 4502                    indent_edits.push((point..point, text));
 4503                }
 4504            }
 4505            editor.edit(indent_edits, cx);
 4506        });
 4507    }
 4508
 4509    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4510        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4511            original_indent_columns: Vec::new(),
 4512        });
 4513        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4514    }
 4515
 4516    fn insert_with_autoindent_mode(
 4517        &mut self,
 4518        text: &str,
 4519        autoindent_mode: Option<AutoindentMode>,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) {
 4523        if self.read_only(cx) {
 4524            return;
 4525        }
 4526
 4527        let text: Arc<str> = text.into();
 4528        self.transact(window, cx, |this, window, cx| {
 4529            let old_selections = this.selections.all_adjusted(cx);
 4530            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4531                let anchors = {
 4532                    let snapshot = buffer.read(cx);
 4533                    old_selections
 4534                        .iter()
 4535                        .map(|s| {
 4536                            let anchor = snapshot.anchor_after(s.head());
 4537                            s.map(|_| anchor)
 4538                        })
 4539                        .collect::<Vec<_>>()
 4540                };
 4541                buffer.edit(
 4542                    old_selections
 4543                        .iter()
 4544                        .map(|s| (s.start..s.end, text.clone())),
 4545                    autoindent_mode,
 4546                    cx,
 4547                );
 4548                anchors
 4549            });
 4550
 4551            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4552                s.select_anchors(selection_anchors);
 4553            });
 4554
 4555            cx.notify();
 4556        });
 4557    }
 4558
 4559    fn trigger_completion_on_input(
 4560        &mut self,
 4561        text: &str,
 4562        trigger_in_words: bool,
 4563        window: &mut Window,
 4564        cx: &mut Context<Self>,
 4565    ) {
 4566        let completions_source = self
 4567            .context_menu
 4568            .borrow()
 4569            .as_ref()
 4570            .and_then(|menu| match menu {
 4571                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4572                CodeContextMenu::CodeActions(_) => None,
 4573            });
 4574
 4575        match completions_source {
 4576            Some(CompletionsMenuSource::Words) => {
 4577                self.show_word_completions(&ShowWordCompletions, window, cx)
 4578            }
 4579            Some(CompletionsMenuSource::Normal)
 4580            | Some(CompletionsMenuSource::SnippetChoices)
 4581            | None
 4582                if self.is_completion_trigger(
 4583                    text,
 4584                    trigger_in_words,
 4585                    completions_source.is_some(),
 4586                    cx,
 4587                ) =>
 4588            {
 4589                self.show_completions(
 4590                    &ShowCompletions {
 4591                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4592                    },
 4593                    window,
 4594                    cx,
 4595                )
 4596            }
 4597            _ => {
 4598                self.hide_context_menu(window, cx);
 4599            }
 4600        }
 4601    }
 4602
 4603    fn is_completion_trigger(
 4604        &self,
 4605        text: &str,
 4606        trigger_in_words: bool,
 4607        menu_is_open: bool,
 4608        cx: &mut Context<Self>,
 4609    ) -> bool {
 4610        let position = self.selections.newest_anchor().head();
 4611        let multibuffer = self.buffer.read(cx);
 4612        let Some(buffer) = position
 4613            .buffer_id
 4614            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4615        else {
 4616            return false;
 4617        };
 4618
 4619        if let Some(completion_provider) = &self.completion_provider {
 4620            completion_provider.is_completion_trigger(
 4621                &buffer,
 4622                position.text_anchor,
 4623                text,
 4624                trigger_in_words,
 4625                menu_is_open,
 4626                cx,
 4627            )
 4628        } else {
 4629            false
 4630        }
 4631    }
 4632
 4633    /// If any empty selections is touching the start of its innermost containing autoclose
 4634    /// region, expand it to select the brackets.
 4635    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4636        let selections = self.selections.all::<usize>(cx);
 4637        let buffer = self.buffer.read(cx).read(cx);
 4638        let new_selections = self
 4639            .selections_with_autoclose_regions(selections, &buffer)
 4640            .map(|(mut selection, region)| {
 4641                if !selection.is_empty() {
 4642                    return selection;
 4643                }
 4644
 4645                if let Some(region) = region {
 4646                    let mut range = region.range.to_offset(&buffer);
 4647                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4648                        range.start -= region.pair.start.len();
 4649                        if buffer.contains_str_at(range.start, &region.pair.start)
 4650                            && buffer.contains_str_at(range.end, &region.pair.end)
 4651                        {
 4652                            range.end += region.pair.end.len();
 4653                            selection.start = range.start;
 4654                            selection.end = range.end;
 4655
 4656                            return selection;
 4657                        }
 4658                    }
 4659                }
 4660
 4661                let always_treat_brackets_as_autoclosed = buffer
 4662                    .language_settings_at(selection.start, cx)
 4663                    .always_treat_brackets_as_autoclosed;
 4664
 4665                if !always_treat_brackets_as_autoclosed {
 4666                    return selection;
 4667                }
 4668
 4669                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4670                    for (pair, enabled) in scope.brackets() {
 4671                        if !enabled || !pair.close {
 4672                            continue;
 4673                        }
 4674
 4675                        if buffer.contains_str_at(selection.start, &pair.end) {
 4676                            let pair_start_len = pair.start.len();
 4677                            if buffer.contains_str_at(
 4678                                selection.start.saturating_sub(pair_start_len),
 4679                                &pair.start,
 4680                            ) {
 4681                                selection.start -= pair_start_len;
 4682                                selection.end += pair.end.len();
 4683
 4684                                return selection;
 4685                            }
 4686                        }
 4687                    }
 4688                }
 4689
 4690                selection
 4691            })
 4692            .collect();
 4693
 4694        drop(buffer);
 4695        self.change_selections(None, window, cx, |selections| {
 4696            selections.select(new_selections)
 4697        });
 4698    }
 4699
 4700    /// Iterate the given selections, and for each one, find the smallest surrounding
 4701    /// autoclose region. This uses the ordering of the selections and the autoclose
 4702    /// regions to avoid repeated comparisons.
 4703    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4704        &'a self,
 4705        selections: impl IntoIterator<Item = Selection<D>>,
 4706        buffer: &'a MultiBufferSnapshot,
 4707    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4708        let mut i = 0;
 4709        let mut regions = self.autoclose_regions.as_slice();
 4710        selections.into_iter().map(move |selection| {
 4711            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4712
 4713            let mut enclosing = None;
 4714            while let Some(pair_state) = regions.get(i) {
 4715                if pair_state.range.end.to_offset(buffer) < range.start {
 4716                    regions = &regions[i + 1..];
 4717                    i = 0;
 4718                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4719                    break;
 4720                } else {
 4721                    if pair_state.selection_id == selection.id {
 4722                        enclosing = Some(pair_state);
 4723                    }
 4724                    i += 1;
 4725                }
 4726            }
 4727
 4728            (selection, enclosing)
 4729        })
 4730    }
 4731
 4732    /// Remove any autoclose regions that no longer contain their selection.
 4733    fn invalidate_autoclose_regions(
 4734        &mut self,
 4735        mut selections: &[Selection<Anchor>],
 4736        buffer: &MultiBufferSnapshot,
 4737    ) {
 4738        self.autoclose_regions.retain(|state| {
 4739            let mut i = 0;
 4740            while let Some(selection) = selections.get(i) {
 4741                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4742                    selections = &selections[1..];
 4743                    continue;
 4744                }
 4745                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4746                    break;
 4747                }
 4748                if selection.id == state.selection_id {
 4749                    return true;
 4750                } else {
 4751                    i += 1;
 4752                }
 4753            }
 4754            false
 4755        });
 4756    }
 4757
 4758    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4759        let offset = position.to_offset(buffer);
 4760        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4761        if offset > word_range.start && kind == Some(CharKind::Word) {
 4762            Some(
 4763                buffer
 4764                    .text_for_range(word_range.start..offset)
 4765                    .collect::<String>(),
 4766            )
 4767        } else {
 4768            None
 4769        }
 4770    }
 4771
 4772    pub fn toggle_inline_values(
 4773        &mut self,
 4774        _: &ToggleInlineValues,
 4775        _: &mut Window,
 4776        cx: &mut Context<Self>,
 4777    ) {
 4778        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4779
 4780        self.refresh_inline_values(cx);
 4781    }
 4782
 4783    pub fn toggle_inlay_hints(
 4784        &mut self,
 4785        _: &ToggleInlayHints,
 4786        _: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        self.refresh_inlay_hints(
 4790            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4791            cx,
 4792        );
 4793    }
 4794
 4795    pub fn inlay_hints_enabled(&self) -> bool {
 4796        self.inlay_hint_cache.enabled
 4797    }
 4798
 4799    pub fn inline_values_enabled(&self) -> bool {
 4800        self.inline_value_cache.enabled
 4801    }
 4802
 4803    #[cfg(any(test, feature = "test-support"))]
 4804    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4805        self.display_map
 4806            .read(cx)
 4807            .current_inlays()
 4808            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4809            .cloned()
 4810            .collect()
 4811    }
 4812
 4813    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4814        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4815            return;
 4816        }
 4817
 4818        let reason_description = reason.description();
 4819        let ignore_debounce = matches!(
 4820            reason,
 4821            InlayHintRefreshReason::SettingsChange(_)
 4822                | InlayHintRefreshReason::Toggle(_)
 4823                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4824                | InlayHintRefreshReason::ModifiersChanged(_)
 4825        );
 4826        let (invalidate_cache, required_languages) = match reason {
 4827            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4828                match self.inlay_hint_cache.modifiers_override(enabled) {
 4829                    Some(enabled) => {
 4830                        if enabled {
 4831                            (InvalidationStrategy::RefreshRequested, None)
 4832                        } else {
 4833                            self.splice_inlays(
 4834                                &self
 4835                                    .visible_inlay_hints(cx)
 4836                                    .iter()
 4837                                    .map(|inlay| inlay.id)
 4838                                    .collect::<Vec<InlayId>>(),
 4839                                Vec::new(),
 4840                                cx,
 4841                            );
 4842                            return;
 4843                        }
 4844                    }
 4845                    None => return,
 4846                }
 4847            }
 4848            InlayHintRefreshReason::Toggle(enabled) => {
 4849                if self.inlay_hint_cache.toggle(enabled) {
 4850                    if enabled {
 4851                        (InvalidationStrategy::RefreshRequested, None)
 4852                    } else {
 4853                        self.splice_inlays(
 4854                            &self
 4855                                .visible_inlay_hints(cx)
 4856                                .iter()
 4857                                .map(|inlay| inlay.id)
 4858                                .collect::<Vec<InlayId>>(),
 4859                            Vec::new(),
 4860                            cx,
 4861                        );
 4862                        return;
 4863                    }
 4864                } else {
 4865                    return;
 4866                }
 4867            }
 4868            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4869                match self.inlay_hint_cache.update_settings(
 4870                    &self.buffer,
 4871                    new_settings,
 4872                    self.visible_inlay_hints(cx),
 4873                    cx,
 4874                ) {
 4875                    ControlFlow::Break(Some(InlaySplice {
 4876                        to_remove,
 4877                        to_insert,
 4878                    })) => {
 4879                        self.splice_inlays(&to_remove, to_insert, cx);
 4880                        return;
 4881                    }
 4882                    ControlFlow::Break(None) => return,
 4883                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4884                }
 4885            }
 4886            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4887                if let Some(InlaySplice {
 4888                    to_remove,
 4889                    to_insert,
 4890                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4891                {
 4892                    self.splice_inlays(&to_remove, to_insert, cx);
 4893                }
 4894                self.display_map.update(cx, |display_map, _| {
 4895                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4896                });
 4897                return;
 4898            }
 4899            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4900            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4901                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4902            }
 4903            InlayHintRefreshReason::RefreshRequested => {
 4904                (InvalidationStrategy::RefreshRequested, None)
 4905            }
 4906        };
 4907
 4908        if let Some(InlaySplice {
 4909            to_remove,
 4910            to_insert,
 4911        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4912            reason_description,
 4913            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4914            invalidate_cache,
 4915            ignore_debounce,
 4916            cx,
 4917        ) {
 4918            self.splice_inlays(&to_remove, to_insert, cx);
 4919        }
 4920    }
 4921
 4922    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4923        self.display_map
 4924            .read(cx)
 4925            .current_inlays()
 4926            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4927            .cloned()
 4928            .collect()
 4929    }
 4930
 4931    pub fn excerpts_for_inlay_hints_query(
 4932        &self,
 4933        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4934        cx: &mut Context<Editor>,
 4935    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4936        let Some(project) = self.project.as_ref() else {
 4937            return HashMap::default();
 4938        };
 4939        let project = project.read(cx);
 4940        let multi_buffer = self.buffer().read(cx);
 4941        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4942        let multi_buffer_visible_start = self
 4943            .scroll_manager
 4944            .anchor()
 4945            .anchor
 4946            .to_point(&multi_buffer_snapshot);
 4947        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4948            multi_buffer_visible_start
 4949                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4950            Bias::Left,
 4951        );
 4952        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4953        multi_buffer_snapshot
 4954            .range_to_buffer_ranges(multi_buffer_visible_range)
 4955            .into_iter()
 4956            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4957            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4958                let buffer_file = project::File::from_dyn(buffer.file())?;
 4959                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4960                let worktree_entry = buffer_worktree
 4961                    .read(cx)
 4962                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4963                if worktree_entry.is_ignored {
 4964                    return None;
 4965                }
 4966
 4967                let language = buffer.language()?;
 4968                if let Some(restrict_to_languages) = restrict_to_languages {
 4969                    if !restrict_to_languages.contains(language) {
 4970                        return None;
 4971                    }
 4972                }
 4973                Some((
 4974                    excerpt_id,
 4975                    (
 4976                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4977                        buffer.version().clone(),
 4978                        excerpt_visible_range,
 4979                    ),
 4980                ))
 4981            })
 4982            .collect()
 4983    }
 4984
 4985    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4986        TextLayoutDetails {
 4987            text_system: window.text_system().clone(),
 4988            editor_style: self.style.clone().unwrap(),
 4989            rem_size: window.rem_size(),
 4990            scroll_anchor: self.scroll_manager.anchor(),
 4991            visible_rows: self.visible_line_count(),
 4992            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4993        }
 4994    }
 4995
 4996    pub fn splice_inlays(
 4997        &self,
 4998        to_remove: &[InlayId],
 4999        to_insert: Vec<Inlay>,
 5000        cx: &mut Context<Self>,
 5001    ) {
 5002        self.display_map.update(cx, |display_map, cx| {
 5003            display_map.splice_inlays(to_remove, to_insert, cx)
 5004        });
 5005        cx.notify();
 5006    }
 5007
 5008    fn trigger_on_type_formatting(
 5009        &self,
 5010        input: String,
 5011        window: &mut Window,
 5012        cx: &mut Context<Self>,
 5013    ) -> Option<Task<Result<()>>> {
 5014        if input.len() != 1 {
 5015            return None;
 5016        }
 5017
 5018        let project = self.project.as_ref()?;
 5019        let position = self.selections.newest_anchor().head();
 5020        let (buffer, buffer_position) = self
 5021            .buffer
 5022            .read(cx)
 5023            .text_anchor_for_position(position, cx)?;
 5024
 5025        let settings = language_settings::language_settings(
 5026            buffer
 5027                .read(cx)
 5028                .language_at(buffer_position)
 5029                .map(|l| l.name()),
 5030            buffer.read(cx).file(),
 5031            cx,
 5032        );
 5033        if !settings.use_on_type_format {
 5034            return None;
 5035        }
 5036
 5037        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5038        // hence we do LSP request & edit on host side only — add formats to host's history.
 5039        let push_to_lsp_host_history = true;
 5040        // If this is not the host, append its history with new edits.
 5041        let push_to_client_history = project.read(cx).is_via_collab();
 5042
 5043        let on_type_formatting = project.update(cx, |project, cx| {
 5044            project.on_type_format(
 5045                buffer.clone(),
 5046                buffer_position,
 5047                input,
 5048                push_to_lsp_host_history,
 5049                cx,
 5050            )
 5051        });
 5052        Some(cx.spawn_in(window, async move |editor, cx| {
 5053            if let Some(transaction) = on_type_formatting.await? {
 5054                if push_to_client_history {
 5055                    buffer
 5056                        .update(cx, |buffer, _| {
 5057                            buffer.push_transaction(transaction, Instant::now());
 5058                            buffer.finalize_last_transaction();
 5059                        })
 5060                        .ok();
 5061                }
 5062                editor.update(cx, |editor, cx| {
 5063                    editor.refresh_document_highlights(cx);
 5064                })?;
 5065            }
 5066            Ok(())
 5067        }))
 5068    }
 5069
 5070    pub fn show_word_completions(
 5071        &mut self,
 5072        _: &ShowWordCompletions,
 5073        window: &mut Window,
 5074        cx: &mut Context<Self>,
 5075    ) {
 5076        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5077    }
 5078
 5079    pub fn show_completions(
 5080        &mut self,
 5081        options: &ShowCompletions,
 5082        window: &mut Window,
 5083        cx: &mut Context<Self>,
 5084    ) {
 5085        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5086    }
 5087
 5088    fn open_or_update_completions_menu(
 5089        &mut self,
 5090        requested_source: Option<CompletionsMenuSource>,
 5091        trigger: Option<&str>,
 5092        window: &mut Window,
 5093        cx: &mut Context<Self>,
 5094    ) {
 5095        if self.pending_rename.is_some() {
 5096            return;
 5097        }
 5098
 5099        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5100
 5101        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5102        // inserted and selected. To handle that case, the start of the selection is used so that
 5103        // the menu starts with all choices.
 5104        let position = self
 5105            .selections
 5106            .newest_anchor()
 5107            .start
 5108            .bias_right(&multibuffer_snapshot);
 5109        if position.diff_base_anchor.is_some() {
 5110            return;
 5111        }
 5112        let (buffer, buffer_position) =
 5113            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5114                output
 5115            } else {
 5116                return;
 5117            };
 5118        let buffer_snapshot = buffer.read(cx).snapshot();
 5119
 5120        let query: Option<Arc<String>> =
 5121            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5122
 5123        drop(multibuffer_snapshot);
 5124
 5125        let provider = match requested_source {
 5126            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5127            Some(CompletionsMenuSource::Words) => None,
 5128            Some(CompletionsMenuSource::SnippetChoices) => {
 5129                log::error!("bug: SnippetChoices requested_source is not handled");
 5130                None
 5131            }
 5132        };
 5133
 5134        let sort_completions = provider
 5135            .as_ref()
 5136            .map_or(false, |provider| provider.sort_completions());
 5137
 5138        let filter_completions = provider
 5139            .as_ref()
 5140            .map_or(true, |provider| provider.filter_completions());
 5141
 5142        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5143            if filter_completions {
 5144                menu.filter(query.clone(), provider.clone(), window, cx);
 5145            }
 5146            // When `is_incomplete` is false, no need to re-query completions when the current query
 5147            // is a suffix of the initial query.
 5148            if !menu.is_incomplete {
 5149                // If the new query is a suffix of the old query (typing more characters) and
 5150                // the previous result was complete, the existing completions can be filtered.
 5151                //
 5152                // Note that this is always true for snippet completions.
 5153                let query_matches = match (&menu.initial_query, &query) {
 5154                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5155                    (None, _) => true,
 5156                    _ => false,
 5157                };
 5158                if query_matches {
 5159                    let position_matches = if menu.initial_position == position {
 5160                        true
 5161                    } else {
 5162                        let snapshot = self.buffer.read(cx).read(cx);
 5163                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5164                    };
 5165                    if position_matches {
 5166                        return;
 5167                    }
 5168                }
 5169            }
 5170        };
 5171
 5172        let trigger_kind = match trigger {
 5173            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5174                CompletionTriggerKind::TRIGGER_CHARACTER
 5175            }
 5176            _ => CompletionTriggerKind::INVOKED,
 5177        };
 5178        let completion_context = CompletionContext {
 5179            trigger_character: trigger.and_then(|trigger| {
 5180                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5181                    Some(String::from(trigger))
 5182                } else {
 5183                    None
 5184                }
 5185            }),
 5186            trigger_kind,
 5187        };
 5188
 5189        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5190            buffer_snapshot.surrounding_word(buffer_position)
 5191        {
 5192            let word_to_exclude = buffer_snapshot
 5193                .text_for_range(word_range.clone())
 5194                .collect::<String>();
 5195            (
 5196                buffer_snapshot.anchor_before(word_range.start)
 5197                    ..buffer_snapshot.anchor_after(buffer_position),
 5198                Some(word_to_exclude),
 5199            )
 5200        } else {
 5201            (buffer_position..buffer_position, None)
 5202        };
 5203
 5204        let language = buffer_snapshot
 5205            .language_at(buffer_position)
 5206            .map(|language| language.name());
 5207
 5208        let completion_settings =
 5209            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5210
 5211        let show_completion_documentation = buffer_snapshot
 5212            .settings_at(buffer_position, cx)
 5213            .show_completion_documentation;
 5214
 5215        // The document can be large, so stay in reasonable bounds when searching for words,
 5216        // otherwise completion pop-up might be slow to appear.
 5217        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5218        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5219        let min_word_search = buffer_snapshot.clip_point(
 5220            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5221            Bias::Left,
 5222        );
 5223        let max_word_search = buffer_snapshot.clip_point(
 5224            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5225            Bias::Right,
 5226        );
 5227        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5228            ..buffer_snapshot.point_to_offset(max_word_search);
 5229
 5230        let skip_digits = query
 5231            .as_ref()
 5232            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5233
 5234        let (mut words, provider_responses) = match &provider {
 5235            Some(provider) => {
 5236                let provider_responses = provider.completions(
 5237                    position.excerpt_id,
 5238                    &buffer,
 5239                    buffer_position,
 5240                    completion_context,
 5241                    window,
 5242                    cx,
 5243                );
 5244
 5245                let words = match completion_settings.words {
 5246                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5247                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5248                        .background_spawn(async move {
 5249                            buffer_snapshot.words_in_range(WordsQuery {
 5250                                fuzzy_contents: None,
 5251                                range: word_search_range,
 5252                                skip_digits,
 5253                            })
 5254                        }),
 5255                };
 5256
 5257                (words, provider_responses)
 5258            }
 5259            None => (
 5260                cx.background_spawn(async move {
 5261                    buffer_snapshot.words_in_range(WordsQuery {
 5262                        fuzzy_contents: None,
 5263                        range: word_search_range,
 5264                        skip_digits,
 5265                    })
 5266                }),
 5267                Task::ready(Ok(Vec::new())),
 5268            ),
 5269        };
 5270
 5271        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5272
 5273        let id = post_inc(&mut self.next_completion_id);
 5274        let task = cx.spawn_in(window, async move |editor, cx| {
 5275            let Ok(()) = editor.update(cx, |this, _| {
 5276                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5277            }) else {
 5278                return;
 5279            };
 5280
 5281            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5282            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5283            let mut completions = Vec::new();
 5284            let mut is_incomplete = false;
 5285            if let Some(provider_responses) = provider_responses.await.log_err() {
 5286                if !provider_responses.is_empty() {
 5287                    for response in provider_responses {
 5288                        completions.extend(response.completions);
 5289                        is_incomplete = is_incomplete || response.is_incomplete;
 5290                    }
 5291                    if completion_settings.words == WordsCompletionMode::Fallback {
 5292                        words = Task::ready(BTreeMap::default());
 5293                    }
 5294                }
 5295            }
 5296
 5297            let mut words = words.await;
 5298            if let Some(word_to_exclude) = &word_to_exclude {
 5299                words.remove(word_to_exclude);
 5300            }
 5301            for lsp_completion in &completions {
 5302                words.remove(&lsp_completion.new_text);
 5303            }
 5304            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5305                replace_range: word_replace_range.clone(),
 5306                new_text: word.clone(),
 5307                label: CodeLabel::plain(word, None),
 5308                icon_path: None,
 5309                documentation: None,
 5310                source: CompletionSource::BufferWord {
 5311                    word_range,
 5312                    resolved: false,
 5313                },
 5314                insert_text_mode: Some(InsertTextMode::AS_IS),
 5315                confirm: None,
 5316            }));
 5317
 5318            let menu = if completions.is_empty() {
 5319                None
 5320            } else {
 5321                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5322                    let languages = editor
 5323                        .workspace
 5324                        .as_ref()
 5325                        .and_then(|(workspace, _)| workspace.upgrade())
 5326                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5327                    let menu = CompletionsMenu::new(
 5328                        id,
 5329                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5330                        sort_completions,
 5331                        show_completion_documentation,
 5332                        position,
 5333                        query.clone(),
 5334                        is_incomplete,
 5335                        buffer.clone(),
 5336                        completions.into(),
 5337                        snippet_sort_order,
 5338                        languages,
 5339                        language,
 5340                        cx,
 5341                    );
 5342
 5343                    let query = if filter_completions { query } else { None };
 5344                    let matches_task = if let Some(query) = query {
 5345                        menu.do_async_filtering(query, cx)
 5346                    } else {
 5347                        Task::ready(menu.unfiltered_matches())
 5348                    };
 5349                    (menu, matches_task)
 5350                }) else {
 5351                    return;
 5352                };
 5353
 5354                let matches = matches_task.await;
 5355
 5356                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5357                    // Newer menu already set, so exit.
 5358                    match editor.context_menu.borrow().as_ref() {
 5359                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5360                            if prev_menu.id > id {
 5361                                return;
 5362                            }
 5363                        }
 5364                        _ => {}
 5365                    };
 5366
 5367                    // Only valid to take prev_menu because it the new menu is immediately set
 5368                    // below, or the menu is hidden.
 5369                    match editor.context_menu.borrow_mut().take() {
 5370                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5371                            let position_matches =
 5372                                if prev_menu.initial_position == menu.initial_position {
 5373                                    true
 5374                                } else {
 5375                                    let snapshot = editor.buffer.read(cx).read(cx);
 5376                                    prev_menu.initial_position.to_offset(&snapshot)
 5377                                        == menu.initial_position.to_offset(&snapshot)
 5378                                };
 5379                            if position_matches {
 5380                                // Preserve markdown cache before `set_filter_results` because it will
 5381                                // try to populate the documentation cache.
 5382                                menu.preserve_markdown_cache(prev_menu);
 5383                            }
 5384                        }
 5385                        _ => {}
 5386                    };
 5387
 5388                    menu.set_filter_results(matches, provider, window, cx);
 5389                }) else {
 5390                    return;
 5391                };
 5392
 5393                menu.visible().then_some(menu)
 5394            };
 5395
 5396            editor
 5397                .update_in(cx, |editor, window, cx| {
 5398                    if editor.focus_handle.is_focused(window) {
 5399                        if let Some(menu) = menu {
 5400                            *editor.context_menu.borrow_mut() =
 5401                                Some(CodeContextMenu::Completions(menu));
 5402
 5403                            crate::hover_popover::hide_hover(editor, cx);
 5404                            if editor.show_edit_predictions_in_menu() {
 5405                                editor.update_visible_inline_completion(window, cx);
 5406                            } else {
 5407                                editor.discard_inline_completion(false, cx);
 5408                            }
 5409
 5410                            cx.notify();
 5411                            return;
 5412                        }
 5413                    }
 5414
 5415                    if editor.completion_tasks.len() <= 1 {
 5416                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5417                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5418                        // If it was already hidden and we don't show inline completions in the menu, we should
 5419                        // also show the inline-completion when available.
 5420                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5421                            editor.update_visible_inline_completion(window, cx);
 5422                        }
 5423                    }
 5424                })
 5425                .ok();
 5426        });
 5427
 5428        self.completion_tasks.push((id, task));
 5429    }
 5430
 5431    #[cfg(feature = "test-support")]
 5432    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5433        let menu = self.context_menu.borrow();
 5434        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5435            let completions = menu.completions.borrow();
 5436            Some(completions.to_vec())
 5437        } else {
 5438            None
 5439        }
 5440    }
 5441
 5442    pub fn with_completions_menu_matching_id<R>(
 5443        &self,
 5444        id: CompletionId,
 5445        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5446    ) -> R {
 5447        let mut context_menu = self.context_menu.borrow_mut();
 5448        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5449            return f(None);
 5450        };
 5451        if completions_menu.id != id {
 5452            return f(None);
 5453        }
 5454        f(Some(completions_menu))
 5455    }
 5456
 5457    pub fn confirm_completion(
 5458        &mut self,
 5459        action: &ConfirmCompletion,
 5460        window: &mut Window,
 5461        cx: &mut Context<Self>,
 5462    ) -> Option<Task<Result<()>>> {
 5463        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5464        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5465    }
 5466
 5467    pub fn confirm_completion_insert(
 5468        &mut self,
 5469        _: &ConfirmCompletionInsert,
 5470        window: &mut Window,
 5471        cx: &mut Context<Self>,
 5472    ) -> Option<Task<Result<()>>> {
 5473        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5474        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5475    }
 5476
 5477    pub fn confirm_completion_replace(
 5478        &mut self,
 5479        _: &ConfirmCompletionReplace,
 5480        window: &mut Window,
 5481        cx: &mut Context<Self>,
 5482    ) -> Option<Task<Result<()>>> {
 5483        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5484        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5485    }
 5486
 5487    pub fn compose_completion(
 5488        &mut self,
 5489        action: &ComposeCompletion,
 5490        window: &mut Window,
 5491        cx: &mut Context<Self>,
 5492    ) -> Option<Task<Result<()>>> {
 5493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5494        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5495    }
 5496
 5497    fn do_completion(
 5498        &mut self,
 5499        item_ix: Option<usize>,
 5500        intent: CompletionIntent,
 5501        window: &mut Window,
 5502        cx: &mut Context<Editor>,
 5503    ) -> Option<Task<Result<()>>> {
 5504        use language::ToOffset as _;
 5505
 5506        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5507        else {
 5508            return None;
 5509        };
 5510
 5511        let candidate_id = {
 5512            let entries = completions_menu.entries.borrow();
 5513            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5514            if self.show_edit_predictions_in_menu() {
 5515                self.discard_inline_completion(true, cx);
 5516            }
 5517            mat.candidate_id
 5518        };
 5519
 5520        let completion = completions_menu
 5521            .completions
 5522            .borrow()
 5523            .get(candidate_id)?
 5524            .clone();
 5525        cx.stop_propagation();
 5526
 5527        let buffer_handle = completions_menu.buffer.clone();
 5528
 5529        let CompletionEdit {
 5530            new_text,
 5531            snippet,
 5532            replace_range,
 5533        } = process_completion_for_edit(
 5534            &completion,
 5535            intent,
 5536            &buffer_handle,
 5537            &completions_menu.initial_position.text_anchor,
 5538            cx,
 5539        );
 5540
 5541        let buffer = buffer_handle.read(cx);
 5542        let snapshot = self.buffer.read(cx).snapshot(cx);
 5543        let newest_anchor = self.selections.newest_anchor();
 5544        let replace_range_multibuffer = {
 5545            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5546            let multibuffer_anchor = snapshot
 5547                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5548                .unwrap()
 5549                ..snapshot
 5550                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5551                    .unwrap();
 5552            multibuffer_anchor.start.to_offset(&snapshot)
 5553                ..multibuffer_anchor.end.to_offset(&snapshot)
 5554        };
 5555        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5556            return None;
 5557        }
 5558
 5559        let old_text = buffer
 5560            .text_for_range(replace_range.clone())
 5561            .collect::<String>();
 5562        let lookbehind = newest_anchor
 5563            .start
 5564            .text_anchor
 5565            .to_offset(buffer)
 5566            .saturating_sub(replace_range.start);
 5567        let lookahead = replace_range
 5568            .end
 5569            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5570        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5571        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5572
 5573        let selections = self.selections.all::<usize>(cx);
 5574        let mut ranges = Vec::new();
 5575        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5576
 5577        for selection in &selections {
 5578            let range = if selection.id == newest_anchor.id {
 5579                replace_range_multibuffer.clone()
 5580            } else {
 5581                let mut range = selection.range();
 5582
 5583                // if prefix is present, don't duplicate it
 5584                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5585                    range.start = range.start.saturating_sub(lookbehind);
 5586
 5587                    // if suffix is also present, mimic the newest cursor and replace it
 5588                    if selection.id != newest_anchor.id
 5589                        && snapshot.contains_str_at(range.end, suffix)
 5590                    {
 5591                        range.end += lookahead;
 5592                    }
 5593                }
 5594                range
 5595            };
 5596
 5597            ranges.push(range.clone());
 5598
 5599            if !self.linked_edit_ranges.is_empty() {
 5600                let start_anchor = snapshot.anchor_before(range.start);
 5601                let end_anchor = snapshot.anchor_after(range.end);
 5602                if let Some(ranges) = self
 5603                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5604                {
 5605                    for (buffer, edits) in ranges {
 5606                        linked_edits
 5607                            .entry(buffer.clone())
 5608                            .or_default()
 5609                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5610                    }
 5611                }
 5612            }
 5613        }
 5614
 5615        let common_prefix_len = old_text
 5616            .chars()
 5617            .zip(new_text.chars())
 5618            .take_while(|(a, b)| a == b)
 5619            .map(|(a, _)| a.len_utf8())
 5620            .sum::<usize>();
 5621
 5622        cx.emit(EditorEvent::InputHandled {
 5623            utf16_range_to_replace: None,
 5624            text: new_text[common_prefix_len..].into(),
 5625        });
 5626
 5627        self.transact(window, cx, |this, window, cx| {
 5628            if let Some(mut snippet) = snippet {
 5629                snippet.text = new_text.to_string();
 5630                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5631            } else {
 5632                this.buffer.update(cx, |buffer, cx| {
 5633                    let auto_indent = match completion.insert_text_mode {
 5634                        Some(InsertTextMode::AS_IS) => None,
 5635                        _ => this.autoindent_mode.clone(),
 5636                    };
 5637                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5638                    buffer.edit(edits, auto_indent, cx);
 5639                });
 5640            }
 5641            for (buffer, edits) in linked_edits {
 5642                buffer.update(cx, |buffer, cx| {
 5643                    let snapshot = buffer.snapshot();
 5644                    let edits = edits
 5645                        .into_iter()
 5646                        .map(|(range, text)| {
 5647                            use text::ToPoint as TP;
 5648                            let end_point = TP::to_point(&range.end, &snapshot);
 5649                            let start_point = TP::to_point(&range.start, &snapshot);
 5650                            (start_point..end_point, text)
 5651                        })
 5652                        .sorted_by_key(|(range, _)| range.start);
 5653                    buffer.edit(edits, None, cx);
 5654                })
 5655            }
 5656
 5657            this.refresh_inline_completion(true, false, window, cx);
 5658        });
 5659
 5660        let show_new_completions_on_confirm = completion
 5661            .confirm
 5662            .as_ref()
 5663            .map_or(false, |confirm| confirm(intent, window, cx));
 5664        if show_new_completions_on_confirm {
 5665            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5666        }
 5667
 5668        let provider = self.completion_provider.as_ref()?;
 5669        drop(completion);
 5670        let apply_edits = provider.apply_additional_edits_for_completion(
 5671            buffer_handle,
 5672            completions_menu.completions.clone(),
 5673            candidate_id,
 5674            true,
 5675            cx,
 5676        );
 5677
 5678        let editor_settings = EditorSettings::get_global(cx);
 5679        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5680            // After the code completion is finished, users often want to know what signatures are needed.
 5681            // so we should automatically call signature_help
 5682            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5683        }
 5684
 5685        Some(cx.foreground_executor().spawn(async move {
 5686            apply_edits.await?;
 5687            Ok(())
 5688        }))
 5689    }
 5690
 5691    pub fn toggle_code_actions(
 5692        &mut self,
 5693        action: &ToggleCodeActions,
 5694        window: &mut Window,
 5695        cx: &mut Context<Self>,
 5696    ) {
 5697        let quick_launch = action.quick_launch;
 5698        let mut context_menu = self.context_menu.borrow_mut();
 5699        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5700            if code_actions.deployed_from == action.deployed_from {
 5701                // Toggle if we're selecting the same one
 5702                *context_menu = None;
 5703                cx.notify();
 5704                return;
 5705            } else {
 5706                // Otherwise, clear it and start a new one
 5707                *context_menu = None;
 5708                cx.notify();
 5709            }
 5710        }
 5711        drop(context_menu);
 5712        let snapshot = self.snapshot(window, cx);
 5713        let deployed_from = action.deployed_from.clone();
 5714        let mut task = self.code_actions_task.take();
 5715        let action = action.clone();
 5716        cx.spawn_in(window, async move |editor, cx| {
 5717            while let Some(prev_task) = task {
 5718                prev_task.await.log_err();
 5719                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5720            }
 5721
 5722            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5723                if editor.focus_handle.is_focused(window) {
 5724                    let multibuffer_point = match &action.deployed_from {
 5725                        Some(CodeActionSource::Indicator(row)) => {
 5726                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5727                        }
 5728                        _ => editor.selections.newest::<Point>(cx).head(),
 5729                    };
 5730                    let (buffer, buffer_row) = snapshot
 5731                        .buffer_snapshot
 5732                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5733                        .and_then(|(buffer_snapshot, range)| {
 5734                            editor
 5735                                .buffer
 5736                                .read(cx)
 5737                                .buffer(buffer_snapshot.remote_id())
 5738                                .map(|buffer| (buffer, range.start.row))
 5739                        })?;
 5740                    let (_, code_actions) = editor
 5741                        .available_code_actions
 5742                        .clone()
 5743                        .and_then(|(location, code_actions)| {
 5744                            let snapshot = location.buffer.read(cx).snapshot();
 5745                            let point_range = location.range.to_point(&snapshot);
 5746                            let point_range = point_range.start.row..=point_range.end.row;
 5747                            if point_range.contains(&buffer_row) {
 5748                                Some((location, code_actions))
 5749                            } else {
 5750                                None
 5751                            }
 5752                        })
 5753                        .unzip();
 5754                    let buffer_id = buffer.read(cx).remote_id();
 5755                    let tasks = editor
 5756                        .tasks
 5757                        .get(&(buffer_id, buffer_row))
 5758                        .map(|t| Arc::new(t.to_owned()));
 5759                    if tasks.is_none() && code_actions.is_none() {
 5760                        return None;
 5761                    }
 5762
 5763                    editor.completion_tasks.clear();
 5764                    editor.discard_inline_completion(false, cx);
 5765                    let task_context =
 5766                        tasks
 5767                            .as_ref()
 5768                            .zip(editor.project.clone())
 5769                            .map(|(tasks, project)| {
 5770                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5771                            });
 5772
 5773                    Some(cx.spawn_in(window, async move |editor, cx| {
 5774                        let task_context = match task_context {
 5775                            Some(task_context) => task_context.await,
 5776                            None => None,
 5777                        };
 5778                        let resolved_tasks =
 5779                            tasks
 5780                                .zip(task_context.clone())
 5781                                .map(|(tasks, task_context)| ResolvedTasks {
 5782                                    templates: tasks.resolve(&task_context).collect(),
 5783                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5784                                        multibuffer_point.row,
 5785                                        tasks.column,
 5786                                    )),
 5787                                });
 5788                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5789                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5790                                maybe!({
 5791                                    let project = editor.project.as_ref()?;
 5792                                    let dap_store = project.read(cx).dap_store();
 5793                                    let mut scenarios = vec![];
 5794                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5795                                    let buffer = buffer.read(cx);
 5796                                    let language = buffer.language()?;
 5797                                    let file = buffer.file();
 5798                                    let debug_adapter =
 5799                                        language_settings(language.name().into(), file, cx)
 5800                                            .debuggers
 5801                                            .first()
 5802                                            .map(SharedString::from)
 5803                                            .or_else(|| {
 5804                                                language
 5805                                                    .config()
 5806                                                    .debuggers
 5807                                                    .first()
 5808                                                    .map(SharedString::from)
 5809                                            })?;
 5810
 5811                                    dap_store.update(cx, |dap_store, cx| {
 5812                                        for (_, task) in &resolved_tasks.templates {
 5813                                            if let Some(scenario) = dap_store
 5814                                                .debug_scenario_for_build_task(
 5815                                                    task.original_task().clone(),
 5816                                                    debug_adapter.clone().into(),
 5817                                                    task.display_label().to_owned().into(),
 5818                                                    cx,
 5819                                                )
 5820                                            {
 5821                                                scenarios.push(scenario);
 5822                                            }
 5823                                        }
 5824                                    });
 5825                                    Some(scenarios)
 5826                                })
 5827                                .unwrap_or_default()
 5828                            } else {
 5829                                vec![]
 5830                            }
 5831                        })?;
 5832                        let spawn_straight_away = quick_launch
 5833                            && resolved_tasks
 5834                                .as_ref()
 5835                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5836                            && code_actions
 5837                                .as_ref()
 5838                                .map_or(true, |actions| actions.is_empty())
 5839                            && debug_scenarios.is_empty();
 5840                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5841                            crate::hover_popover::hide_hover(editor, cx);
 5842                            *editor.context_menu.borrow_mut() =
 5843                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5844                                    buffer,
 5845                                    actions: CodeActionContents::new(
 5846                                        resolved_tasks,
 5847                                        code_actions,
 5848                                        debug_scenarios,
 5849                                        task_context.unwrap_or_default(),
 5850                                    ),
 5851                                    selected_item: Default::default(),
 5852                                    scroll_handle: UniformListScrollHandle::default(),
 5853                                    deployed_from,
 5854                                }));
 5855                            if spawn_straight_away {
 5856                                if let Some(task) = editor.confirm_code_action(
 5857                                    &ConfirmCodeAction { item_ix: Some(0) },
 5858                                    window,
 5859                                    cx,
 5860                                ) {
 5861                                    cx.notify();
 5862                                    return task;
 5863                                }
 5864                            }
 5865                            cx.notify();
 5866                            Task::ready(Ok(()))
 5867                        }) {
 5868                            task.await
 5869                        } else {
 5870                            Ok(())
 5871                        }
 5872                    }))
 5873                } else {
 5874                    Some(Task::ready(Ok(())))
 5875                }
 5876            })?;
 5877            if let Some(task) = spawned_test_task {
 5878                task.await?;
 5879            }
 5880
 5881            anyhow::Ok(())
 5882        })
 5883        .detach_and_log_err(cx);
 5884    }
 5885
 5886    pub fn confirm_code_action(
 5887        &mut self,
 5888        action: &ConfirmCodeAction,
 5889        window: &mut Window,
 5890        cx: &mut Context<Self>,
 5891    ) -> Option<Task<Result<()>>> {
 5892        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5893
 5894        let actions_menu =
 5895            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5896                menu
 5897            } else {
 5898                return None;
 5899            };
 5900
 5901        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5902        let action = actions_menu.actions.get(action_ix)?;
 5903        let title = action.label();
 5904        let buffer = actions_menu.buffer;
 5905        let workspace = self.workspace()?;
 5906
 5907        match action {
 5908            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5909                workspace.update(cx, |workspace, cx| {
 5910                    workspace.schedule_resolved_task(
 5911                        task_source_kind,
 5912                        resolved_task,
 5913                        false,
 5914                        window,
 5915                        cx,
 5916                    );
 5917
 5918                    Some(Task::ready(Ok(())))
 5919                })
 5920            }
 5921            CodeActionsItem::CodeAction {
 5922                excerpt_id,
 5923                action,
 5924                provider,
 5925            } => {
 5926                let apply_code_action =
 5927                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5928                let workspace = workspace.downgrade();
 5929                Some(cx.spawn_in(window, async move |editor, cx| {
 5930                    let project_transaction = apply_code_action.await?;
 5931                    Self::open_project_transaction(
 5932                        &editor,
 5933                        workspace,
 5934                        project_transaction,
 5935                        title,
 5936                        cx,
 5937                    )
 5938                    .await
 5939                }))
 5940            }
 5941            CodeActionsItem::DebugScenario(scenario) => {
 5942                let context = actions_menu.actions.context.clone();
 5943
 5944                workspace.update(cx, |workspace, cx| {
 5945                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5946                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5947                });
 5948                Some(Task::ready(Ok(())))
 5949            }
 5950        }
 5951    }
 5952
 5953    pub async fn open_project_transaction(
 5954        this: &WeakEntity<Editor>,
 5955        workspace: WeakEntity<Workspace>,
 5956        transaction: ProjectTransaction,
 5957        title: String,
 5958        cx: &mut AsyncWindowContext,
 5959    ) -> Result<()> {
 5960        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5961        cx.update(|_, cx| {
 5962            entries.sort_unstable_by_key(|(buffer, _)| {
 5963                buffer.read(cx).file().map(|f| f.path().clone())
 5964            });
 5965        })?;
 5966
 5967        // If the project transaction's edits are all contained within this editor, then
 5968        // avoid opening a new editor to display them.
 5969
 5970        if let Some((buffer, transaction)) = entries.first() {
 5971            if entries.len() == 1 {
 5972                let excerpt = this.update(cx, |editor, cx| {
 5973                    editor
 5974                        .buffer()
 5975                        .read(cx)
 5976                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5977                })?;
 5978                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5979                    if excerpted_buffer == *buffer {
 5980                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5981                            let excerpt_range = excerpt_range.to_offset(buffer);
 5982                            buffer
 5983                                .edited_ranges_for_transaction::<usize>(transaction)
 5984                                .all(|range| {
 5985                                    excerpt_range.start <= range.start
 5986                                        && excerpt_range.end >= range.end
 5987                                })
 5988                        })?;
 5989
 5990                        if all_edits_within_excerpt {
 5991                            return Ok(());
 5992                        }
 5993                    }
 5994                }
 5995            }
 5996        } else {
 5997            return Ok(());
 5998        }
 5999
 6000        let mut ranges_to_highlight = Vec::new();
 6001        let excerpt_buffer = cx.new(|cx| {
 6002            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6003            for (buffer_handle, transaction) in &entries {
 6004                let edited_ranges = buffer_handle
 6005                    .read(cx)
 6006                    .edited_ranges_for_transaction::<Point>(transaction)
 6007                    .collect::<Vec<_>>();
 6008                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6009                    PathKey::for_buffer(buffer_handle, cx),
 6010                    buffer_handle.clone(),
 6011                    edited_ranges,
 6012                    DEFAULT_MULTIBUFFER_CONTEXT,
 6013                    cx,
 6014                );
 6015
 6016                ranges_to_highlight.extend(ranges);
 6017            }
 6018            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6019            multibuffer
 6020        })?;
 6021
 6022        workspace.update_in(cx, |workspace, window, cx| {
 6023            let project = workspace.project().clone();
 6024            let editor =
 6025                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6026            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6027            editor.update(cx, |editor, cx| {
 6028                editor.highlight_background::<Self>(
 6029                    &ranges_to_highlight,
 6030                    |theme| theme.editor_highlighted_line_background,
 6031                    cx,
 6032                );
 6033            });
 6034        })?;
 6035
 6036        Ok(())
 6037    }
 6038
 6039    pub fn clear_code_action_providers(&mut self) {
 6040        self.code_action_providers.clear();
 6041        self.available_code_actions.take();
 6042    }
 6043
 6044    pub fn add_code_action_provider(
 6045        &mut self,
 6046        provider: Rc<dyn CodeActionProvider>,
 6047        window: &mut Window,
 6048        cx: &mut Context<Self>,
 6049    ) {
 6050        if self
 6051            .code_action_providers
 6052            .iter()
 6053            .any(|existing_provider| existing_provider.id() == provider.id())
 6054        {
 6055            return;
 6056        }
 6057
 6058        self.code_action_providers.push(provider);
 6059        self.refresh_code_actions(window, cx);
 6060    }
 6061
 6062    pub fn remove_code_action_provider(
 6063        &mut self,
 6064        id: Arc<str>,
 6065        window: &mut Window,
 6066        cx: &mut Context<Self>,
 6067    ) {
 6068        self.code_action_providers
 6069            .retain(|provider| provider.id() != id);
 6070        self.refresh_code_actions(window, cx);
 6071    }
 6072
 6073    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6074        !self.code_action_providers.is_empty()
 6075            && EditorSettings::get_global(cx).toolbar.code_actions
 6076    }
 6077
 6078    pub fn has_available_code_actions(&self) -> bool {
 6079        self.available_code_actions
 6080            .as_ref()
 6081            .is_some_and(|(_, actions)| !actions.is_empty())
 6082    }
 6083
 6084    fn render_inline_code_actions(
 6085        &self,
 6086        icon_size: ui::IconSize,
 6087        display_row: DisplayRow,
 6088        is_active: bool,
 6089        cx: &mut Context<Self>,
 6090    ) -> AnyElement {
 6091        let show_tooltip = !self.context_menu_visible();
 6092        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6093            .icon_size(icon_size)
 6094            .shape(ui::IconButtonShape::Square)
 6095            .style(ButtonStyle::Transparent)
 6096            .icon_color(ui::Color::Hidden)
 6097            .toggle_state(is_active)
 6098            .when(show_tooltip, |this| {
 6099                this.tooltip({
 6100                    let focus_handle = self.focus_handle.clone();
 6101                    move |window, cx| {
 6102                        Tooltip::for_action_in(
 6103                            "Toggle Code Actions",
 6104                            &ToggleCodeActions {
 6105                                deployed_from: None,
 6106                                quick_launch: false,
 6107                            },
 6108                            &focus_handle,
 6109                            window,
 6110                            cx,
 6111                        )
 6112                    }
 6113                })
 6114            })
 6115            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6116                window.focus(&editor.focus_handle(cx));
 6117                editor.toggle_code_actions(
 6118                    &crate::actions::ToggleCodeActions {
 6119                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6120                            display_row,
 6121                        )),
 6122                        quick_launch: false,
 6123                    },
 6124                    window,
 6125                    cx,
 6126                );
 6127            }))
 6128            .into_any_element()
 6129    }
 6130
 6131    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6132        &self.context_menu
 6133    }
 6134
 6135    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6136        let newest_selection = self.selections.newest_anchor().clone();
 6137        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6138        let buffer = self.buffer.read(cx);
 6139        if newest_selection.head().diff_base_anchor.is_some() {
 6140            return None;
 6141        }
 6142        let (start_buffer, start) =
 6143            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6144        let (end_buffer, end) =
 6145            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6146        if start_buffer != end_buffer {
 6147            return None;
 6148        }
 6149
 6150        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6151            cx.background_executor()
 6152                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6153                .await;
 6154
 6155            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6156                let providers = this.code_action_providers.clone();
 6157                let tasks = this
 6158                    .code_action_providers
 6159                    .iter()
 6160                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6161                    .collect::<Vec<_>>();
 6162                (providers, tasks)
 6163            })?;
 6164
 6165            let mut actions = Vec::new();
 6166            for (provider, provider_actions) in
 6167                providers.into_iter().zip(future::join_all(tasks).await)
 6168            {
 6169                if let Some(provider_actions) = provider_actions.log_err() {
 6170                    actions.extend(provider_actions.into_iter().map(|action| {
 6171                        AvailableCodeAction {
 6172                            excerpt_id: newest_selection.start.excerpt_id,
 6173                            action,
 6174                            provider: provider.clone(),
 6175                        }
 6176                    }));
 6177                }
 6178            }
 6179
 6180            this.update(cx, |this, cx| {
 6181                this.available_code_actions = if actions.is_empty() {
 6182                    None
 6183                } else {
 6184                    Some((
 6185                        Location {
 6186                            buffer: start_buffer,
 6187                            range: start..end,
 6188                        },
 6189                        actions.into(),
 6190                    ))
 6191                };
 6192                cx.notify();
 6193            })
 6194        }));
 6195        None
 6196    }
 6197
 6198    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6199        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6200            self.show_git_blame_inline = false;
 6201
 6202            self.show_git_blame_inline_delay_task =
 6203                Some(cx.spawn_in(window, async move |this, cx| {
 6204                    cx.background_executor().timer(delay).await;
 6205
 6206                    this.update(cx, |this, cx| {
 6207                        this.show_git_blame_inline = true;
 6208                        cx.notify();
 6209                    })
 6210                    .log_err();
 6211                }));
 6212        }
 6213    }
 6214
 6215    fn show_blame_popover(
 6216        &mut self,
 6217        blame_entry: &BlameEntry,
 6218        position: gpui::Point<Pixels>,
 6219        cx: &mut Context<Self>,
 6220    ) {
 6221        if let Some(state) = &mut self.inline_blame_popover {
 6222            state.hide_task.take();
 6223            cx.notify();
 6224        } else {
 6225            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6226            let show_task = cx.spawn(async move |editor, cx| {
 6227                cx.background_executor()
 6228                    .timer(std::time::Duration::from_millis(delay))
 6229                    .await;
 6230                editor
 6231                    .update(cx, |editor, cx| {
 6232                        if let Some(state) = &mut editor.inline_blame_popover {
 6233                            state.show_task = None;
 6234                            cx.notify();
 6235                        }
 6236                    })
 6237                    .ok();
 6238            });
 6239            let Some(blame) = self.blame.as_ref() else {
 6240                return;
 6241            };
 6242            let blame = blame.read(cx);
 6243            let details = blame.details_for_entry(&blame_entry);
 6244            let markdown = cx.new(|cx| {
 6245                Markdown::new(
 6246                    details
 6247                        .as_ref()
 6248                        .map(|message| message.message.clone())
 6249                        .unwrap_or_default(),
 6250                    None,
 6251                    None,
 6252                    cx,
 6253                )
 6254            });
 6255            self.inline_blame_popover = Some(InlineBlamePopover {
 6256                position,
 6257                show_task: Some(show_task),
 6258                hide_task: None,
 6259                popover_bounds: None,
 6260                popover_state: InlineBlamePopoverState {
 6261                    scroll_handle: ScrollHandle::new(),
 6262                    commit_message: details,
 6263                    markdown,
 6264                },
 6265            });
 6266        }
 6267    }
 6268
 6269    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6270        if let Some(state) = &mut self.inline_blame_popover {
 6271            if state.show_task.is_some() {
 6272                self.inline_blame_popover.take();
 6273                cx.notify();
 6274            } else {
 6275                let hide_task = cx.spawn(async move |editor, cx| {
 6276                    cx.background_executor()
 6277                        .timer(std::time::Duration::from_millis(100))
 6278                        .await;
 6279                    editor
 6280                        .update(cx, |editor, cx| {
 6281                            editor.inline_blame_popover.take();
 6282                            cx.notify();
 6283                        })
 6284                        .ok();
 6285                });
 6286                state.hide_task = Some(hide_task);
 6287            }
 6288        }
 6289    }
 6290
 6291    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6292        if self.pending_rename.is_some() {
 6293            return None;
 6294        }
 6295
 6296        let provider = self.semantics_provider.clone()?;
 6297        let buffer = self.buffer.read(cx);
 6298        let newest_selection = self.selections.newest_anchor().clone();
 6299        let cursor_position = newest_selection.head();
 6300        let (cursor_buffer, cursor_buffer_position) =
 6301            buffer.text_anchor_for_position(cursor_position, cx)?;
 6302        let (tail_buffer, tail_buffer_position) =
 6303            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6304        if cursor_buffer != tail_buffer {
 6305            return None;
 6306        }
 6307
 6308        let snapshot = cursor_buffer.read(cx).snapshot();
 6309        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6310        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6311        if start_word_range != end_word_range {
 6312            self.document_highlights_task.take();
 6313            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6314            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6315            return None;
 6316        }
 6317
 6318        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6319        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6320            cx.background_executor()
 6321                .timer(Duration::from_millis(debounce))
 6322                .await;
 6323
 6324            let highlights = if let Some(highlights) = cx
 6325                .update(|cx| {
 6326                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6327                })
 6328                .ok()
 6329                .flatten()
 6330            {
 6331                highlights.await.log_err()
 6332            } else {
 6333                None
 6334            };
 6335
 6336            if let Some(highlights) = highlights {
 6337                this.update(cx, |this, cx| {
 6338                    if this.pending_rename.is_some() {
 6339                        return;
 6340                    }
 6341
 6342                    let buffer_id = cursor_position.buffer_id;
 6343                    let buffer = this.buffer.read(cx);
 6344                    if !buffer
 6345                        .text_anchor_for_position(cursor_position, cx)
 6346                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6347                    {
 6348                        return;
 6349                    }
 6350
 6351                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6352                    let mut write_ranges = Vec::new();
 6353                    let mut read_ranges = Vec::new();
 6354                    for highlight in highlights {
 6355                        for (excerpt_id, excerpt_range) in
 6356                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6357                        {
 6358                            let start = highlight
 6359                                .range
 6360                                .start
 6361                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6362                            let end = highlight
 6363                                .range
 6364                                .end
 6365                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6366                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6367                                continue;
 6368                            }
 6369
 6370                            let range = Anchor {
 6371                                buffer_id,
 6372                                excerpt_id,
 6373                                text_anchor: start,
 6374                                diff_base_anchor: None,
 6375                            }..Anchor {
 6376                                buffer_id,
 6377                                excerpt_id,
 6378                                text_anchor: end,
 6379                                diff_base_anchor: None,
 6380                            };
 6381                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6382                                write_ranges.push(range);
 6383                            } else {
 6384                                read_ranges.push(range);
 6385                            }
 6386                        }
 6387                    }
 6388
 6389                    this.highlight_background::<DocumentHighlightRead>(
 6390                        &read_ranges,
 6391                        |theme| theme.editor_document_highlight_read_background,
 6392                        cx,
 6393                    );
 6394                    this.highlight_background::<DocumentHighlightWrite>(
 6395                        &write_ranges,
 6396                        |theme| theme.editor_document_highlight_write_background,
 6397                        cx,
 6398                    );
 6399                    cx.notify();
 6400                })
 6401                .log_err();
 6402            }
 6403        }));
 6404        None
 6405    }
 6406
 6407    fn prepare_highlight_query_from_selection(
 6408        &mut self,
 6409        cx: &mut Context<Editor>,
 6410    ) -> Option<(String, Range<Anchor>)> {
 6411        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6412            return None;
 6413        }
 6414        if !EditorSettings::get_global(cx).selection_highlight {
 6415            return None;
 6416        }
 6417        if self.selections.count() != 1 || self.selections.line_mode {
 6418            return None;
 6419        }
 6420        let selection = self.selections.newest::<Point>(cx);
 6421        if selection.is_empty() || selection.start.row != selection.end.row {
 6422            return None;
 6423        }
 6424        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6425        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6426        let query = multi_buffer_snapshot
 6427            .text_for_range(selection_anchor_range.clone())
 6428            .collect::<String>();
 6429        if query.trim().is_empty() {
 6430            return None;
 6431        }
 6432        Some((query, selection_anchor_range))
 6433    }
 6434
 6435    fn update_selection_occurrence_highlights(
 6436        &mut self,
 6437        query_text: String,
 6438        query_range: Range<Anchor>,
 6439        multi_buffer_range_to_query: Range<Point>,
 6440        use_debounce: bool,
 6441        window: &mut Window,
 6442        cx: &mut Context<Editor>,
 6443    ) -> Task<()> {
 6444        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6445        cx.spawn_in(window, async move |editor, cx| {
 6446            if use_debounce {
 6447                cx.background_executor()
 6448                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6449                    .await;
 6450            }
 6451            let match_task = cx.background_spawn(async move {
 6452                let buffer_ranges = multi_buffer_snapshot
 6453                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6454                    .into_iter()
 6455                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6456                let mut match_ranges = Vec::new();
 6457                let Ok(regex) = project::search::SearchQuery::text(
 6458                    query_text.clone(),
 6459                    false,
 6460                    false,
 6461                    false,
 6462                    Default::default(),
 6463                    Default::default(),
 6464                    false,
 6465                    None,
 6466                ) else {
 6467                    return Vec::default();
 6468                };
 6469                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6470                    match_ranges.extend(
 6471                        regex
 6472                            .search(&buffer_snapshot, Some(search_range.clone()))
 6473                            .await
 6474                            .into_iter()
 6475                            .filter_map(|match_range| {
 6476                                let match_start = buffer_snapshot
 6477                                    .anchor_after(search_range.start + match_range.start);
 6478                                let match_end = buffer_snapshot
 6479                                    .anchor_before(search_range.start + match_range.end);
 6480                                let match_anchor_range = Anchor::range_in_buffer(
 6481                                    excerpt_id,
 6482                                    buffer_snapshot.remote_id(),
 6483                                    match_start..match_end,
 6484                                );
 6485                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6486                            }),
 6487                    );
 6488                }
 6489                match_ranges
 6490            });
 6491            let match_ranges = match_task.await;
 6492            editor
 6493                .update_in(cx, |editor, _, cx| {
 6494                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6495                    if !match_ranges.is_empty() {
 6496                        editor.highlight_background::<SelectedTextHighlight>(
 6497                            &match_ranges,
 6498                            |theme| theme.editor_document_highlight_bracket_background,
 6499                            cx,
 6500                        )
 6501                    }
 6502                })
 6503                .log_err();
 6504        })
 6505    }
 6506
 6507    fn refresh_selected_text_highlights(
 6508        &mut self,
 6509        on_buffer_edit: bool,
 6510        window: &mut Window,
 6511        cx: &mut Context<Editor>,
 6512    ) {
 6513        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6514        else {
 6515            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6516            self.quick_selection_highlight_task.take();
 6517            self.debounced_selection_highlight_task.take();
 6518            return;
 6519        };
 6520        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6521        if on_buffer_edit
 6522            || self
 6523                .quick_selection_highlight_task
 6524                .as_ref()
 6525                .map_or(true, |(prev_anchor_range, _)| {
 6526                    prev_anchor_range != &query_range
 6527                })
 6528        {
 6529            let multi_buffer_visible_start = self
 6530                .scroll_manager
 6531                .anchor()
 6532                .anchor
 6533                .to_point(&multi_buffer_snapshot);
 6534            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6535                multi_buffer_visible_start
 6536                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6537                Bias::Left,
 6538            );
 6539            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6540            self.quick_selection_highlight_task = Some((
 6541                query_range.clone(),
 6542                self.update_selection_occurrence_highlights(
 6543                    query_text.clone(),
 6544                    query_range.clone(),
 6545                    multi_buffer_visible_range,
 6546                    false,
 6547                    window,
 6548                    cx,
 6549                ),
 6550            ));
 6551        }
 6552        if on_buffer_edit
 6553            || self
 6554                .debounced_selection_highlight_task
 6555                .as_ref()
 6556                .map_or(true, |(prev_anchor_range, _)| {
 6557                    prev_anchor_range != &query_range
 6558                })
 6559        {
 6560            let multi_buffer_start = multi_buffer_snapshot
 6561                .anchor_before(0)
 6562                .to_point(&multi_buffer_snapshot);
 6563            let multi_buffer_end = multi_buffer_snapshot
 6564                .anchor_after(multi_buffer_snapshot.len())
 6565                .to_point(&multi_buffer_snapshot);
 6566            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6567            self.debounced_selection_highlight_task = Some((
 6568                query_range.clone(),
 6569                self.update_selection_occurrence_highlights(
 6570                    query_text,
 6571                    query_range,
 6572                    multi_buffer_full_range,
 6573                    true,
 6574                    window,
 6575                    cx,
 6576                ),
 6577            ));
 6578        }
 6579    }
 6580
 6581    pub fn refresh_inline_completion(
 6582        &mut self,
 6583        debounce: bool,
 6584        user_requested: bool,
 6585        window: &mut Window,
 6586        cx: &mut Context<Self>,
 6587    ) -> Option<()> {
 6588        let provider = self.edit_prediction_provider()?;
 6589        let cursor = self.selections.newest_anchor().head();
 6590        let (buffer, cursor_buffer_position) =
 6591            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6592
 6593        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6594            self.discard_inline_completion(false, cx);
 6595            return None;
 6596        }
 6597
 6598        if !user_requested
 6599            && (!self.should_show_edit_predictions()
 6600                || !self.is_focused(window)
 6601                || buffer.read(cx).is_empty())
 6602        {
 6603            self.discard_inline_completion(false, cx);
 6604            return None;
 6605        }
 6606
 6607        self.update_visible_inline_completion(window, cx);
 6608        provider.refresh(
 6609            self.project.clone(),
 6610            buffer,
 6611            cursor_buffer_position,
 6612            debounce,
 6613            cx,
 6614        );
 6615        Some(())
 6616    }
 6617
 6618    fn show_edit_predictions_in_menu(&self) -> bool {
 6619        match self.edit_prediction_settings {
 6620            EditPredictionSettings::Disabled => false,
 6621            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6622        }
 6623    }
 6624
 6625    pub fn edit_predictions_enabled(&self) -> bool {
 6626        match self.edit_prediction_settings {
 6627            EditPredictionSettings::Disabled => false,
 6628            EditPredictionSettings::Enabled { .. } => true,
 6629        }
 6630    }
 6631
 6632    fn edit_prediction_requires_modifier(&self) -> bool {
 6633        match self.edit_prediction_settings {
 6634            EditPredictionSettings::Disabled => false,
 6635            EditPredictionSettings::Enabled {
 6636                preview_requires_modifier,
 6637                ..
 6638            } => preview_requires_modifier,
 6639        }
 6640    }
 6641
 6642    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6643        if self.edit_prediction_provider.is_none() {
 6644            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6645        } else {
 6646            let selection = self.selections.newest_anchor();
 6647            let cursor = selection.head();
 6648
 6649            if let Some((buffer, cursor_buffer_position)) =
 6650                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6651            {
 6652                self.edit_prediction_settings =
 6653                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6654            }
 6655        }
 6656    }
 6657
 6658    fn edit_prediction_settings_at_position(
 6659        &self,
 6660        buffer: &Entity<Buffer>,
 6661        buffer_position: language::Anchor,
 6662        cx: &App,
 6663    ) -> EditPredictionSettings {
 6664        if !self.mode.is_full()
 6665            || !self.show_inline_completions_override.unwrap_or(true)
 6666            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6667        {
 6668            return EditPredictionSettings::Disabled;
 6669        }
 6670
 6671        let buffer = buffer.read(cx);
 6672
 6673        let file = buffer.file();
 6674
 6675        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6676            return EditPredictionSettings::Disabled;
 6677        };
 6678
 6679        let by_provider = matches!(
 6680            self.menu_inline_completions_policy,
 6681            MenuInlineCompletionsPolicy::ByProvider
 6682        );
 6683
 6684        let show_in_menu = by_provider
 6685            && self
 6686                .edit_prediction_provider
 6687                .as_ref()
 6688                .map_or(false, |provider| {
 6689                    provider.provider.show_completions_in_menu()
 6690                });
 6691
 6692        let preview_requires_modifier =
 6693            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6694
 6695        EditPredictionSettings::Enabled {
 6696            show_in_menu,
 6697            preview_requires_modifier,
 6698        }
 6699    }
 6700
 6701    fn should_show_edit_predictions(&self) -> bool {
 6702        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6703    }
 6704
 6705    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6706        matches!(
 6707            self.edit_prediction_preview,
 6708            EditPredictionPreview::Active { .. }
 6709        )
 6710    }
 6711
 6712    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6713        let cursor = self.selections.newest_anchor().head();
 6714        if let Some((buffer, cursor_position)) =
 6715            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6716        {
 6717            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6718        } else {
 6719            false
 6720        }
 6721    }
 6722
 6723    pub fn supports_minimap(&self, cx: &App) -> bool {
 6724        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6725    }
 6726
 6727    fn edit_predictions_enabled_in_buffer(
 6728        &self,
 6729        buffer: &Entity<Buffer>,
 6730        buffer_position: language::Anchor,
 6731        cx: &App,
 6732    ) -> bool {
 6733        maybe!({
 6734            if self.read_only(cx) {
 6735                return Some(false);
 6736            }
 6737            let provider = self.edit_prediction_provider()?;
 6738            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6739                return Some(false);
 6740            }
 6741            let buffer = buffer.read(cx);
 6742            let Some(file) = buffer.file() else {
 6743                return Some(true);
 6744            };
 6745            let settings = all_language_settings(Some(file), cx);
 6746            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6747        })
 6748        .unwrap_or(false)
 6749    }
 6750
 6751    fn cycle_inline_completion(
 6752        &mut self,
 6753        direction: Direction,
 6754        window: &mut Window,
 6755        cx: &mut Context<Self>,
 6756    ) -> Option<()> {
 6757        let provider = self.edit_prediction_provider()?;
 6758        let cursor = self.selections.newest_anchor().head();
 6759        let (buffer, cursor_buffer_position) =
 6760            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6761        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6762            return None;
 6763        }
 6764
 6765        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6766        self.update_visible_inline_completion(window, cx);
 6767
 6768        Some(())
 6769    }
 6770
 6771    pub fn show_inline_completion(
 6772        &mut self,
 6773        _: &ShowEditPrediction,
 6774        window: &mut Window,
 6775        cx: &mut Context<Self>,
 6776    ) {
 6777        if !self.has_active_inline_completion() {
 6778            self.refresh_inline_completion(false, true, window, cx);
 6779            return;
 6780        }
 6781
 6782        self.update_visible_inline_completion(window, cx);
 6783    }
 6784
 6785    pub fn display_cursor_names(
 6786        &mut self,
 6787        _: &DisplayCursorNames,
 6788        window: &mut Window,
 6789        cx: &mut Context<Self>,
 6790    ) {
 6791        self.show_cursor_names(window, cx);
 6792    }
 6793
 6794    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6795        self.show_cursor_names = true;
 6796        cx.notify();
 6797        cx.spawn_in(window, async move |this, cx| {
 6798            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6799            this.update(cx, |this, cx| {
 6800                this.show_cursor_names = false;
 6801                cx.notify()
 6802            })
 6803            .ok()
 6804        })
 6805        .detach();
 6806    }
 6807
 6808    pub fn next_edit_prediction(
 6809        &mut self,
 6810        _: &NextEditPrediction,
 6811        window: &mut Window,
 6812        cx: &mut Context<Self>,
 6813    ) {
 6814        if self.has_active_inline_completion() {
 6815            self.cycle_inline_completion(Direction::Next, 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 previous_edit_prediction(
 6827        &mut self,
 6828        _: &PreviousEditPrediction,
 6829        window: &mut Window,
 6830        cx: &mut Context<Self>,
 6831    ) {
 6832        if self.has_active_inline_completion() {
 6833            self.cycle_inline_completion(Direction::Prev, window, cx);
 6834        } else {
 6835            let is_copilot_disabled = self
 6836                .refresh_inline_completion(false, true, window, cx)
 6837                .is_none();
 6838            if is_copilot_disabled {
 6839                cx.propagate();
 6840            }
 6841        }
 6842    }
 6843
 6844    pub fn accept_edit_prediction(
 6845        &mut self,
 6846        _: &AcceptEditPrediction,
 6847        window: &mut Window,
 6848        cx: &mut Context<Self>,
 6849    ) {
 6850        if self.show_edit_predictions_in_menu() {
 6851            self.hide_context_menu(window, cx);
 6852        }
 6853
 6854        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6855            return;
 6856        };
 6857
 6858        self.report_inline_completion_event(
 6859            active_inline_completion.completion_id.clone(),
 6860            true,
 6861            cx,
 6862        );
 6863
 6864        match &active_inline_completion.completion {
 6865            InlineCompletion::Move { target, .. } => {
 6866                let target = *target;
 6867
 6868                if let Some(position_map) = &self.last_position_map {
 6869                    if position_map
 6870                        .visible_row_range
 6871                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6872                        || !self.edit_prediction_requires_modifier()
 6873                    {
 6874                        self.unfold_ranges(&[target..target], true, false, cx);
 6875                        // Note that this is also done in vim's handler of the Tab action.
 6876                        self.change_selections(
 6877                            Some(Autoscroll::newest()),
 6878                            window,
 6879                            cx,
 6880                            |selections| {
 6881                                selections.select_anchor_ranges([target..target]);
 6882                            },
 6883                        );
 6884                        self.clear_row_highlights::<EditPredictionPreview>();
 6885
 6886                        self.edit_prediction_preview
 6887                            .set_previous_scroll_position(None);
 6888                    } else {
 6889                        self.edit_prediction_preview
 6890                            .set_previous_scroll_position(Some(
 6891                                position_map.snapshot.scroll_anchor,
 6892                            ));
 6893
 6894                        self.highlight_rows::<EditPredictionPreview>(
 6895                            target..target,
 6896                            cx.theme().colors().editor_highlighted_line_background,
 6897                            RowHighlightOptions {
 6898                                autoscroll: true,
 6899                                ..Default::default()
 6900                            },
 6901                            cx,
 6902                        );
 6903                        self.request_autoscroll(Autoscroll::fit(), cx);
 6904                    }
 6905                }
 6906            }
 6907            InlineCompletion::Edit { edits, .. } => {
 6908                if let Some(provider) = self.edit_prediction_provider() {
 6909                    provider.accept(cx);
 6910                }
 6911
 6912                // Store the transaction ID and selections before applying the edit
 6913                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6914
 6915                let snapshot = self.buffer.read(cx).snapshot(cx);
 6916                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6917
 6918                self.buffer.update(cx, |buffer, cx| {
 6919                    buffer.edit(edits.iter().cloned(), None, cx)
 6920                });
 6921
 6922                self.change_selections(None, window, cx, |s| {
 6923                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6924                });
 6925
 6926                let selections = self.selections.disjoint_anchors();
 6927                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6928                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6929                    if has_new_transaction {
 6930                        self.selection_history
 6931                            .insert_transaction(transaction_id_now, selections);
 6932                    }
 6933                }
 6934
 6935                self.update_visible_inline_completion(window, cx);
 6936                if self.active_inline_completion.is_none() {
 6937                    self.refresh_inline_completion(true, true, window, cx);
 6938                }
 6939
 6940                cx.notify();
 6941            }
 6942        }
 6943
 6944        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6945    }
 6946
 6947    pub fn accept_partial_inline_completion(
 6948        &mut self,
 6949        _: &AcceptPartialEditPrediction,
 6950        window: &mut Window,
 6951        cx: &mut Context<Self>,
 6952    ) {
 6953        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6954            return;
 6955        };
 6956        if self.selections.count() != 1 {
 6957            return;
 6958        }
 6959
 6960        self.report_inline_completion_event(
 6961            active_inline_completion.completion_id.clone(),
 6962            true,
 6963            cx,
 6964        );
 6965
 6966        match &active_inline_completion.completion {
 6967            InlineCompletion::Move { target, .. } => {
 6968                let target = *target;
 6969                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6970                    selections.select_anchor_ranges([target..target]);
 6971                });
 6972            }
 6973            InlineCompletion::Edit { edits, .. } => {
 6974                // Find an insertion that starts at the cursor position.
 6975                let snapshot = self.buffer.read(cx).snapshot(cx);
 6976                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6977                let insertion = edits.iter().find_map(|(range, text)| {
 6978                    let range = range.to_offset(&snapshot);
 6979                    if range.is_empty() && range.start == cursor_offset {
 6980                        Some(text)
 6981                    } else {
 6982                        None
 6983                    }
 6984                });
 6985
 6986                if let Some(text) = insertion {
 6987                    let mut partial_completion = text
 6988                        .chars()
 6989                        .by_ref()
 6990                        .take_while(|c| c.is_alphabetic())
 6991                        .collect::<String>();
 6992                    if partial_completion.is_empty() {
 6993                        partial_completion = text
 6994                            .chars()
 6995                            .by_ref()
 6996                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6997                            .collect::<String>();
 6998                    }
 6999
 7000                    cx.emit(EditorEvent::InputHandled {
 7001                        utf16_range_to_replace: None,
 7002                        text: partial_completion.clone().into(),
 7003                    });
 7004
 7005                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7006
 7007                    self.refresh_inline_completion(true, true, window, cx);
 7008                    cx.notify();
 7009                } else {
 7010                    self.accept_edit_prediction(&Default::default(), window, cx);
 7011                }
 7012            }
 7013        }
 7014    }
 7015
 7016    fn discard_inline_completion(
 7017        &mut self,
 7018        should_report_inline_completion_event: bool,
 7019        cx: &mut Context<Self>,
 7020    ) -> bool {
 7021        if should_report_inline_completion_event {
 7022            let completion_id = self
 7023                .active_inline_completion
 7024                .as_ref()
 7025                .and_then(|active_completion| active_completion.completion_id.clone());
 7026
 7027            self.report_inline_completion_event(completion_id, false, cx);
 7028        }
 7029
 7030        if let Some(provider) = self.edit_prediction_provider() {
 7031            provider.discard(cx);
 7032        }
 7033
 7034        self.take_active_inline_completion(cx)
 7035    }
 7036
 7037    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7038        let Some(provider) = self.edit_prediction_provider() else {
 7039            return;
 7040        };
 7041
 7042        let Some((_, buffer, _)) = self
 7043            .buffer
 7044            .read(cx)
 7045            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7046        else {
 7047            return;
 7048        };
 7049
 7050        let extension = buffer
 7051            .read(cx)
 7052            .file()
 7053            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7054
 7055        let event_type = match accepted {
 7056            true => "Edit Prediction Accepted",
 7057            false => "Edit Prediction Discarded",
 7058        };
 7059        telemetry::event!(
 7060            event_type,
 7061            provider = provider.name(),
 7062            prediction_id = id,
 7063            suggestion_accepted = accepted,
 7064            file_extension = extension,
 7065        );
 7066    }
 7067
 7068    pub fn has_active_inline_completion(&self) -> bool {
 7069        self.active_inline_completion.is_some()
 7070    }
 7071
 7072    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7073        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7074            return false;
 7075        };
 7076
 7077        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7078        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7079        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7080        true
 7081    }
 7082
 7083    /// Returns true when we're displaying the edit prediction popover below the cursor
 7084    /// like we are not previewing and the LSP autocomplete menu is visible
 7085    /// or we are in `when_holding_modifier` mode.
 7086    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7087        if self.edit_prediction_preview_is_active()
 7088            || !self.show_edit_predictions_in_menu()
 7089            || !self.edit_predictions_enabled()
 7090        {
 7091            return false;
 7092        }
 7093
 7094        if self.has_visible_completions_menu() {
 7095            return true;
 7096        }
 7097
 7098        has_completion && self.edit_prediction_requires_modifier()
 7099    }
 7100
 7101    fn handle_modifiers_changed(
 7102        &mut self,
 7103        modifiers: Modifiers,
 7104        position_map: &PositionMap,
 7105        window: &mut Window,
 7106        cx: &mut Context<Self>,
 7107    ) {
 7108        if self.show_edit_predictions_in_menu() {
 7109            self.update_edit_prediction_preview(&modifiers, window, cx);
 7110        }
 7111
 7112        self.update_selection_mode(&modifiers, position_map, window, cx);
 7113
 7114        let mouse_position = window.mouse_position();
 7115        if !position_map.text_hitbox.is_hovered(window) {
 7116            return;
 7117        }
 7118
 7119        self.update_hovered_link(
 7120            position_map.point_for_position(mouse_position),
 7121            &position_map.snapshot,
 7122            modifiers,
 7123            window,
 7124            cx,
 7125        )
 7126    }
 7127
 7128    fn multi_cursor_modifier(
 7129        cursor_event: bool,
 7130        modifiers: &Modifiers,
 7131        cx: &mut Context<Self>,
 7132    ) -> bool {
 7133        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7134        if cursor_event {
 7135            match multi_cursor_setting {
 7136                MultiCursorModifier::Alt => modifiers.alt,
 7137                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7138            }
 7139        } else {
 7140            match multi_cursor_setting {
 7141                MultiCursorModifier::Alt => modifiers.secondary(),
 7142                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7143            }
 7144        }
 7145    }
 7146
 7147    fn columnar_selection_modifiers(multi_cursor_modifier: bool, modifiers: &Modifiers) -> bool {
 7148        modifiers.shift && multi_cursor_modifier && modifiers.number_of_modifiers() == 2
 7149    }
 7150
 7151    fn update_selection_mode(
 7152        &mut self,
 7153        modifiers: &Modifiers,
 7154        position_map: &PositionMap,
 7155        window: &mut Window,
 7156        cx: &mut Context<Self>,
 7157    ) {
 7158        let multi_cursor_modifier = Self::multi_cursor_modifier(true, modifiers, cx);
 7159        if !Self::columnar_selection_modifiers(multi_cursor_modifier, modifiers)
 7160            || self.selections.pending.is_none()
 7161        {
 7162            return;
 7163        }
 7164
 7165        let mouse_position = window.mouse_position();
 7166        let point_for_position = position_map.point_for_position(mouse_position);
 7167        let position = point_for_position.previous_valid;
 7168
 7169        self.select(
 7170            SelectPhase::BeginColumnar {
 7171                position,
 7172                reset: false,
 7173                goal_column: point_for_position.exact_unclipped.column(),
 7174            },
 7175            window,
 7176            cx,
 7177        );
 7178    }
 7179
 7180    fn update_edit_prediction_preview(
 7181        &mut self,
 7182        modifiers: &Modifiers,
 7183        window: &mut Window,
 7184        cx: &mut Context<Self>,
 7185    ) {
 7186        let mut modifiers_held = false;
 7187        if let Some(accept_keystroke) = self
 7188            .accept_edit_prediction_keybind(false, window, cx)
 7189            .keystroke()
 7190        {
 7191            modifiers_held = modifiers_held
 7192                || (&accept_keystroke.modifiers == modifiers
 7193                    && accept_keystroke.modifiers.modified());
 7194        };
 7195        if let Some(accept_partial_keystroke) = self
 7196            .accept_edit_prediction_keybind(true, window, cx)
 7197            .keystroke()
 7198        {
 7199            modifiers_held = modifiers_held
 7200                || (&accept_partial_keystroke.modifiers == modifiers
 7201                    && accept_partial_keystroke.modifiers.modified());
 7202        }
 7203
 7204        if modifiers_held {
 7205            if matches!(
 7206                self.edit_prediction_preview,
 7207                EditPredictionPreview::Inactive { .. }
 7208            ) {
 7209                self.edit_prediction_preview = EditPredictionPreview::Active {
 7210                    previous_scroll_position: None,
 7211                    since: Instant::now(),
 7212                };
 7213
 7214                self.update_visible_inline_completion(window, cx);
 7215                cx.notify();
 7216            }
 7217        } else if let EditPredictionPreview::Active {
 7218            previous_scroll_position,
 7219            since,
 7220        } = self.edit_prediction_preview
 7221        {
 7222            if let (Some(previous_scroll_position), Some(position_map)) =
 7223                (previous_scroll_position, self.last_position_map.as_ref())
 7224            {
 7225                self.set_scroll_position(
 7226                    previous_scroll_position
 7227                        .scroll_position(&position_map.snapshot.display_snapshot),
 7228                    window,
 7229                    cx,
 7230                );
 7231            }
 7232
 7233            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7234                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7235            };
 7236            self.clear_row_highlights::<EditPredictionPreview>();
 7237            self.update_visible_inline_completion(window, cx);
 7238            cx.notify();
 7239        }
 7240    }
 7241
 7242    fn update_visible_inline_completion(
 7243        &mut self,
 7244        _window: &mut Window,
 7245        cx: &mut Context<Self>,
 7246    ) -> Option<()> {
 7247        let selection = self.selections.newest_anchor();
 7248        let cursor = selection.head();
 7249        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7250        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7251        let excerpt_id = cursor.excerpt_id;
 7252
 7253        let show_in_menu = self.show_edit_predictions_in_menu();
 7254        let completions_menu_has_precedence = !show_in_menu
 7255            && (self.context_menu.borrow().is_some()
 7256                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7257
 7258        if completions_menu_has_precedence
 7259            || !offset_selection.is_empty()
 7260            || self
 7261                .active_inline_completion
 7262                .as_ref()
 7263                .map_or(false, |completion| {
 7264                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7265                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7266                    !invalidation_range.contains(&offset_selection.head())
 7267                })
 7268        {
 7269            self.discard_inline_completion(false, cx);
 7270            return None;
 7271        }
 7272
 7273        self.take_active_inline_completion(cx);
 7274        let Some(provider) = self.edit_prediction_provider() else {
 7275            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7276            return None;
 7277        };
 7278
 7279        let (buffer, cursor_buffer_position) =
 7280            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7281
 7282        self.edit_prediction_settings =
 7283            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7284
 7285        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7286
 7287        if self.edit_prediction_indent_conflict {
 7288            let cursor_point = cursor.to_point(&multibuffer);
 7289
 7290            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7291
 7292            if let Some((_, indent)) = indents.iter().next() {
 7293                if indent.len == cursor_point.column {
 7294                    self.edit_prediction_indent_conflict = false;
 7295                }
 7296            }
 7297        }
 7298
 7299        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7300        let edits = inline_completion
 7301            .edits
 7302            .into_iter()
 7303            .flat_map(|(range, new_text)| {
 7304                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7305                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7306                Some((start..end, new_text))
 7307            })
 7308            .collect::<Vec<_>>();
 7309        if edits.is_empty() {
 7310            return None;
 7311        }
 7312
 7313        let first_edit_start = edits.first().unwrap().0.start;
 7314        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7315        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7316
 7317        let last_edit_end = edits.last().unwrap().0.end;
 7318        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7319        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7320
 7321        let cursor_row = cursor.to_point(&multibuffer).row;
 7322
 7323        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7324
 7325        let mut inlay_ids = Vec::new();
 7326        let invalidation_row_range;
 7327        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7328            Some(cursor_row..edit_end_row)
 7329        } else if cursor_row > edit_end_row {
 7330            Some(edit_start_row..cursor_row)
 7331        } else {
 7332            None
 7333        };
 7334        let is_move =
 7335            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7336        let completion = if is_move {
 7337            invalidation_row_range =
 7338                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7339            let target = first_edit_start;
 7340            InlineCompletion::Move { target, snapshot }
 7341        } else {
 7342            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7343                && !self.inline_completions_hidden_for_vim_mode;
 7344
 7345            if show_completions_in_buffer {
 7346                if edits
 7347                    .iter()
 7348                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7349                {
 7350                    let mut inlays = Vec::new();
 7351                    for (range, new_text) in &edits {
 7352                        let inlay = Inlay::inline_completion(
 7353                            post_inc(&mut self.next_inlay_id),
 7354                            range.start,
 7355                            new_text.as_str(),
 7356                        );
 7357                        inlay_ids.push(inlay.id);
 7358                        inlays.push(inlay);
 7359                    }
 7360
 7361                    self.splice_inlays(&[], inlays, cx);
 7362                } else {
 7363                    let background_color = cx.theme().status().deleted_background;
 7364                    self.highlight_text::<InlineCompletionHighlight>(
 7365                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7366                        HighlightStyle {
 7367                            background_color: Some(background_color),
 7368                            ..Default::default()
 7369                        },
 7370                        cx,
 7371                    );
 7372                }
 7373            }
 7374
 7375            invalidation_row_range = edit_start_row..edit_end_row;
 7376
 7377            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7378                if provider.show_tab_accept_marker() {
 7379                    EditDisplayMode::TabAccept
 7380                } else {
 7381                    EditDisplayMode::Inline
 7382                }
 7383            } else {
 7384                EditDisplayMode::DiffPopover
 7385            };
 7386
 7387            InlineCompletion::Edit {
 7388                edits,
 7389                edit_preview: inline_completion.edit_preview,
 7390                display_mode,
 7391                snapshot,
 7392            }
 7393        };
 7394
 7395        let invalidation_range = multibuffer
 7396            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7397            ..multibuffer.anchor_after(Point::new(
 7398                invalidation_row_range.end,
 7399                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7400            ));
 7401
 7402        self.stale_inline_completion_in_menu = None;
 7403        self.active_inline_completion = Some(InlineCompletionState {
 7404            inlay_ids,
 7405            completion,
 7406            completion_id: inline_completion.id,
 7407            invalidation_range,
 7408        });
 7409
 7410        cx.notify();
 7411
 7412        Some(())
 7413    }
 7414
 7415    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7416        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7417    }
 7418
 7419    fn clear_tasks(&mut self) {
 7420        self.tasks.clear()
 7421    }
 7422
 7423    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7424        if self.tasks.insert(key, value).is_some() {
 7425            // This case should hopefully be rare, but just in case...
 7426            log::error!(
 7427                "multiple different run targets found on a single line, only the last target will be rendered"
 7428            )
 7429        }
 7430    }
 7431
 7432    /// Get all display points of breakpoints that will be rendered within editor
 7433    ///
 7434    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7435    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7436    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7437    fn active_breakpoints(
 7438        &self,
 7439        range: Range<DisplayRow>,
 7440        window: &mut Window,
 7441        cx: &mut Context<Self>,
 7442    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7443        let mut breakpoint_display_points = HashMap::default();
 7444
 7445        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7446            return breakpoint_display_points;
 7447        };
 7448
 7449        let snapshot = self.snapshot(window, cx);
 7450
 7451        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7452        let Some(project) = self.project.as_ref() else {
 7453            return breakpoint_display_points;
 7454        };
 7455
 7456        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7457            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7458
 7459        for (buffer_snapshot, range, excerpt_id) in
 7460            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7461        {
 7462            let Some(buffer) = project
 7463                .read(cx)
 7464                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7465            else {
 7466                continue;
 7467            };
 7468            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7469                &buffer,
 7470                Some(
 7471                    buffer_snapshot.anchor_before(range.start)
 7472                        ..buffer_snapshot.anchor_after(range.end),
 7473                ),
 7474                buffer_snapshot,
 7475                cx,
 7476            );
 7477            for (breakpoint, state) in breakpoints {
 7478                let multi_buffer_anchor =
 7479                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7480                let position = multi_buffer_anchor
 7481                    .to_point(&multi_buffer_snapshot)
 7482                    .to_display_point(&snapshot);
 7483
 7484                breakpoint_display_points.insert(
 7485                    position.row(),
 7486                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7487                );
 7488            }
 7489        }
 7490
 7491        breakpoint_display_points
 7492    }
 7493
 7494    fn breakpoint_context_menu(
 7495        &self,
 7496        anchor: Anchor,
 7497        window: &mut Window,
 7498        cx: &mut Context<Self>,
 7499    ) -> Entity<ui::ContextMenu> {
 7500        let weak_editor = cx.weak_entity();
 7501        let focus_handle = self.focus_handle(cx);
 7502
 7503        let row = self
 7504            .buffer
 7505            .read(cx)
 7506            .snapshot(cx)
 7507            .summary_for_anchor::<Point>(&anchor)
 7508            .row;
 7509
 7510        let breakpoint = self
 7511            .breakpoint_at_row(row, window, cx)
 7512            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7513
 7514        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7515            "Edit Log Breakpoint"
 7516        } else {
 7517            "Set Log Breakpoint"
 7518        };
 7519
 7520        let condition_breakpoint_msg = if breakpoint
 7521            .as_ref()
 7522            .is_some_and(|bp| bp.1.condition.is_some())
 7523        {
 7524            "Edit Condition Breakpoint"
 7525        } else {
 7526            "Set Condition Breakpoint"
 7527        };
 7528
 7529        let hit_condition_breakpoint_msg = if breakpoint
 7530            .as_ref()
 7531            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7532        {
 7533            "Edit Hit Condition Breakpoint"
 7534        } else {
 7535            "Set Hit Condition Breakpoint"
 7536        };
 7537
 7538        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7539            "Unset Breakpoint"
 7540        } else {
 7541            "Set Breakpoint"
 7542        };
 7543
 7544        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7545            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7546
 7547        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7548            BreakpointState::Enabled => Some("Disable"),
 7549            BreakpointState::Disabled => Some("Enable"),
 7550        });
 7551
 7552        let (anchor, breakpoint) =
 7553            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7554
 7555        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7556            menu.on_blur_subscription(Subscription::new(|| {}))
 7557                .context(focus_handle)
 7558                .when(run_to_cursor, |this| {
 7559                    let weak_editor = weak_editor.clone();
 7560                    this.entry("Run to cursor", None, move |window, cx| {
 7561                        weak_editor
 7562                            .update(cx, |editor, cx| {
 7563                                editor.change_selections(None, window, cx, |s| {
 7564                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7565                                });
 7566                            })
 7567                            .ok();
 7568
 7569                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7570                    })
 7571                    .separator()
 7572                })
 7573                .when_some(toggle_state_msg, |this, msg| {
 7574                    this.entry(msg, None, {
 7575                        let weak_editor = weak_editor.clone();
 7576                        let breakpoint = breakpoint.clone();
 7577                        move |_window, cx| {
 7578                            weak_editor
 7579                                .update(cx, |this, cx| {
 7580                                    this.edit_breakpoint_at_anchor(
 7581                                        anchor,
 7582                                        breakpoint.as_ref().clone(),
 7583                                        BreakpointEditAction::InvertState,
 7584                                        cx,
 7585                                    );
 7586                                })
 7587                                .log_err();
 7588                        }
 7589                    })
 7590                })
 7591                .entry(set_breakpoint_msg, None, {
 7592                    let weak_editor = weak_editor.clone();
 7593                    let breakpoint = breakpoint.clone();
 7594                    move |_window, cx| {
 7595                        weak_editor
 7596                            .update(cx, |this, cx| {
 7597                                this.edit_breakpoint_at_anchor(
 7598                                    anchor,
 7599                                    breakpoint.as_ref().clone(),
 7600                                    BreakpointEditAction::Toggle,
 7601                                    cx,
 7602                                );
 7603                            })
 7604                            .log_err();
 7605                    }
 7606                })
 7607                .entry(log_breakpoint_msg, None, {
 7608                    let breakpoint = breakpoint.clone();
 7609                    let weak_editor = weak_editor.clone();
 7610                    move |window, cx| {
 7611                        weak_editor
 7612                            .update(cx, |this, cx| {
 7613                                this.add_edit_breakpoint_block(
 7614                                    anchor,
 7615                                    breakpoint.as_ref(),
 7616                                    BreakpointPromptEditAction::Log,
 7617                                    window,
 7618                                    cx,
 7619                                );
 7620                            })
 7621                            .log_err();
 7622                    }
 7623                })
 7624                .entry(condition_breakpoint_msg, None, {
 7625                    let breakpoint = breakpoint.clone();
 7626                    let weak_editor = weak_editor.clone();
 7627                    move |window, cx| {
 7628                        weak_editor
 7629                            .update(cx, |this, cx| {
 7630                                this.add_edit_breakpoint_block(
 7631                                    anchor,
 7632                                    breakpoint.as_ref(),
 7633                                    BreakpointPromptEditAction::Condition,
 7634                                    window,
 7635                                    cx,
 7636                                );
 7637                            })
 7638                            .log_err();
 7639                    }
 7640                })
 7641                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7642                    weak_editor
 7643                        .update(cx, |this, cx| {
 7644                            this.add_edit_breakpoint_block(
 7645                                anchor,
 7646                                breakpoint.as_ref(),
 7647                                BreakpointPromptEditAction::HitCondition,
 7648                                window,
 7649                                cx,
 7650                            );
 7651                        })
 7652                        .log_err();
 7653                })
 7654        })
 7655    }
 7656
 7657    fn render_breakpoint(
 7658        &self,
 7659        position: Anchor,
 7660        row: DisplayRow,
 7661        breakpoint: &Breakpoint,
 7662        state: Option<BreakpointSessionState>,
 7663        cx: &mut Context<Self>,
 7664    ) -> IconButton {
 7665        let is_rejected = state.is_some_and(|s| !s.verified);
 7666        // Is it a breakpoint that shows up when hovering over gutter?
 7667        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7668            (false, false),
 7669            |PhantomBreakpointIndicator {
 7670                 is_active,
 7671                 display_row,
 7672                 collides_with_existing_breakpoint,
 7673             }| {
 7674                (
 7675                    is_active && display_row == row,
 7676                    collides_with_existing_breakpoint,
 7677                )
 7678            },
 7679        );
 7680
 7681        let (color, icon) = {
 7682            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7683                (false, false) => ui::IconName::DebugBreakpoint,
 7684                (true, false) => ui::IconName::DebugLogBreakpoint,
 7685                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7686                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7687            };
 7688
 7689            let color = if is_phantom {
 7690                Color::Hint
 7691            } else if is_rejected {
 7692                Color::Disabled
 7693            } else {
 7694                Color::Debugger
 7695            };
 7696
 7697            (color, icon)
 7698        };
 7699
 7700        let breakpoint = Arc::from(breakpoint.clone());
 7701
 7702        let alt_as_text = gpui::Keystroke {
 7703            modifiers: Modifiers::secondary_key(),
 7704            ..Default::default()
 7705        };
 7706        let primary_action_text = if breakpoint.is_disabled() {
 7707            "Enable breakpoint"
 7708        } else if is_phantom && !collides_with_existing {
 7709            "Set breakpoint"
 7710        } else {
 7711            "Unset breakpoint"
 7712        };
 7713        let focus_handle = self.focus_handle.clone();
 7714
 7715        let meta = if is_rejected {
 7716            SharedString::from("No executable code is associated with this line.")
 7717        } else if collides_with_existing && !breakpoint.is_disabled() {
 7718            SharedString::from(format!(
 7719                "{alt_as_text}-click to disable,\nright-click for more options."
 7720            ))
 7721        } else {
 7722            SharedString::from("Right-click for more options.")
 7723        };
 7724        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7725            .icon_size(IconSize::XSmall)
 7726            .size(ui::ButtonSize::None)
 7727            .when(is_rejected, |this| {
 7728                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7729            })
 7730            .icon_color(color)
 7731            .style(ButtonStyle::Transparent)
 7732            .on_click(cx.listener({
 7733                let breakpoint = breakpoint.clone();
 7734
 7735                move |editor, event: &ClickEvent, window, cx| {
 7736                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7737                        BreakpointEditAction::InvertState
 7738                    } else {
 7739                        BreakpointEditAction::Toggle
 7740                    };
 7741
 7742                    window.focus(&editor.focus_handle(cx));
 7743                    editor.edit_breakpoint_at_anchor(
 7744                        position,
 7745                        breakpoint.as_ref().clone(),
 7746                        edit_action,
 7747                        cx,
 7748                    );
 7749                }
 7750            }))
 7751            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7752                editor.set_breakpoint_context_menu(
 7753                    row,
 7754                    Some(position),
 7755                    event.down.position,
 7756                    window,
 7757                    cx,
 7758                );
 7759            }))
 7760            .tooltip(move |window, cx| {
 7761                Tooltip::with_meta_in(
 7762                    primary_action_text,
 7763                    Some(&ToggleBreakpoint),
 7764                    meta.clone(),
 7765                    &focus_handle,
 7766                    window,
 7767                    cx,
 7768                )
 7769            })
 7770    }
 7771
 7772    fn build_tasks_context(
 7773        project: &Entity<Project>,
 7774        buffer: &Entity<Buffer>,
 7775        buffer_row: u32,
 7776        tasks: &Arc<RunnableTasks>,
 7777        cx: &mut Context<Self>,
 7778    ) -> Task<Option<task::TaskContext>> {
 7779        let position = Point::new(buffer_row, tasks.column);
 7780        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7781        let location = Location {
 7782            buffer: buffer.clone(),
 7783            range: range_start..range_start,
 7784        };
 7785        // Fill in the environmental variables from the tree-sitter captures
 7786        let mut captured_task_variables = TaskVariables::default();
 7787        for (capture_name, value) in tasks.extra_variables.clone() {
 7788            captured_task_variables.insert(
 7789                task::VariableName::Custom(capture_name.into()),
 7790                value.clone(),
 7791            );
 7792        }
 7793        project.update(cx, |project, cx| {
 7794            project.task_store().update(cx, |task_store, cx| {
 7795                task_store.task_context_for_location(captured_task_variables, location, cx)
 7796            })
 7797        })
 7798    }
 7799
 7800    pub fn spawn_nearest_task(
 7801        &mut self,
 7802        action: &SpawnNearestTask,
 7803        window: &mut Window,
 7804        cx: &mut Context<Self>,
 7805    ) {
 7806        let Some((workspace, _)) = self.workspace.clone() else {
 7807            return;
 7808        };
 7809        let Some(project) = self.project.clone() else {
 7810            return;
 7811        };
 7812
 7813        // Try to find a closest, enclosing node using tree-sitter that has a
 7814        // task
 7815        let Some((buffer, buffer_row, tasks)) = self
 7816            .find_enclosing_node_task(cx)
 7817            // Or find the task that's closest in row-distance.
 7818            .or_else(|| self.find_closest_task(cx))
 7819        else {
 7820            return;
 7821        };
 7822
 7823        let reveal_strategy = action.reveal;
 7824        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7825        cx.spawn_in(window, async move |_, cx| {
 7826            let context = task_context.await?;
 7827            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7828
 7829            let resolved = &mut resolved_task.resolved;
 7830            resolved.reveal = reveal_strategy;
 7831
 7832            workspace
 7833                .update_in(cx, |workspace, window, cx| {
 7834                    workspace.schedule_resolved_task(
 7835                        task_source_kind,
 7836                        resolved_task,
 7837                        false,
 7838                        window,
 7839                        cx,
 7840                    );
 7841                })
 7842                .ok()
 7843        })
 7844        .detach();
 7845    }
 7846
 7847    fn find_closest_task(
 7848        &mut self,
 7849        cx: &mut Context<Self>,
 7850    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7851        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7852
 7853        let ((buffer_id, row), tasks) = self
 7854            .tasks
 7855            .iter()
 7856            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7857
 7858        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7859        let tasks = Arc::new(tasks.to_owned());
 7860        Some((buffer, *row, tasks))
 7861    }
 7862
 7863    fn find_enclosing_node_task(
 7864        &mut self,
 7865        cx: &mut Context<Self>,
 7866    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7867        let snapshot = self.buffer.read(cx).snapshot(cx);
 7868        let offset = self.selections.newest::<usize>(cx).head();
 7869        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7870        let buffer_id = excerpt.buffer().remote_id();
 7871
 7872        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7873        let mut cursor = layer.node().walk();
 7874
 7875        while cursor.goto_first_child_for_byte(offset).is_some() {
 7876            if cursor.node().end_byte() == offset {
 7877                cursor.goto_next_sibling();
 7878            }
 7879        }
 7880
 7881        // Ascend to the smallest ancestor that contains the range and has a task.
 7882        loop {
 7883            let node = cursor.node();
 7884            let node_range = node.byte_range();
 7885            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7886
 7887            // Check if this node contains our offset
 7888            if node_range.start <= offset && node_range.end >= offset {
 7889                // If it contains offset, check for task
 7890                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7891                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7892                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7893                }
 7894            }
 7895
 7896            if !cursor.goto_parent() {
 7897                break;
 7898            }
 7899        }
 7900        None
 7901    }
 7902
 7903    fn render_run_indicator(
 7904        &self,
 7905        _style: &EditorStyle,
 7906        is_active: bool,
 7907        row: DisplayRow,
 7908        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7909        cx: &mut Context<Self>,
 7910    ) -> IconButton {
 7911        let color = Color::Muted;
 7912        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7913
 7914        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7915            .shape(ui::IconButtonShape::Square)
 7916            .icon_size(IconSize::XSmall)
 7917            .icon_color(color)
 7918            .toggle_state(is_active)
 7919            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7920                let quick_launch = e.down.button == MouseButton::Left;
 7921                window.focus(&editor.focus_handle(cx));
 7922                editor.toggle_code_actions(
 7923                    &ToggleCodeActions {
 7924                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7925                        quick_launch,
 7926                    },
 7927                    window,
 7928                    cx,
 7929                );
 7930            }))
 7931            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7932                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7933            }))
 7934    }
 7935
 7936    pub fn context_menu_visible(&self) -> bool {
 7937        !self.edit_prediction_preview_is_active()
 7938            && self
 7939                .context_menu
 7940                .borrow()
 7941                .as_ref()
 7942                .map_or(false, |menu| menu.visible())
 7943    }
 7944
 7945    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7946        self.context_menu
 7947            .borrow()
 7948            .as_ref()
 7949            .map(|menu| menu.origin())
 7950    }
 7951
 7952    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7953        self.context_menu_options = Some(options);
 7954    }
 7955
 7956    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7957    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7958
 7959    fn render_edit_prediction_popover(
 7960        &mut self,
 7961        text_bounds: &Bounds<Pixels>,
 7962        content_origin: gpui::Point<Pixels>,
 7963        right_margin: Pixels,
 7964        editor_snapshot: &EditorSnapshot,
 7965        visible_row_range: Range<DisplayRow>,
 7966        scroll_top: f32,
 7967        scroll_bottom: f32,
 7968        line_layouts: &[LineWithInvisibles],
 7969        line_height: Pixels,
 7970        scroll_pixel_position: gpui::Point<Pixels>,
 7971        newest_selection_head: Option<DisplayPoint>,
 7972        editor_width: Pixels,
 7973        style: &EditorStyle,
 7974        window: &mut Window,
 7975        cx: &mut App,
 7976    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7977        if self.mode().is_minimap() {
 7978            return None;
 7979        }
 7980        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7981
 7982        if self.edit_prediction_visible_in_cursor_popover(true) {
 7983            return None;
 7984        }
 7985
 7986        match &active_inline_completion.completion {
 7987            InlineCompletion::Move { target, .. } => {
 7988                let target_display_point = target.to_display_point(editor_snapshot);
 7989
 7990                if self.edit_prediction_requires_modifier() {
 7991                    if !self.edit_prediction_preview_is_active() {
 7992                        return None;
 7993                    }
 7994
 7995                    self.render_edit_prediction_modifier_jump_popover(
 7996                        text_bounds,
 7997                        content_origin,
 7998                        visible_row_range,
 7999                        line_layouts,
 8000                        line_height,
 8001                        scroll_pixel_position,
 8002                        newest_selection_head,
 8003                        target_display_point,
 8004                        window,
 8005                        cx,
 8006                    )
 8007                } else {
 8008                    self.render_edit_prediction_eager_jump_popover(
 8009                        text_bounds,
 8010                        content_origin,
 8011                        editor_snapshot,
 8012                        visible_row_range,
 8013                        scroll_top,
 8014                        scroll_bottom,
 8015                        line_height,
 8016                        scroll_pixel_position,
 8017                        target_display_point,
 8018                        editor_width,
 8019                        window,
 8020                        cx,
 8021                    )
 8022                }
 8023            }
 8024            InlineCompletion::Edit {
 8025                display_mode: EditDisplayMode::Inline,
 8026                ..
 8027            } => None,
 8028            InlineCompletion::Edit {
 8029                display_mode: EditDisplayMode::TabAccept,
 8030                edits,
 8031                ..
 8032            } => {
 8033                let range = &edits.first()?.0;
 8034                let target_display_point = range.end.to_display_point(editor_snapshot);
 8035
 8036                self.render_edit_prediction_end_of_line_popover(
 8037                    "Accept",
 8038                    editor_snapshot,
 8039                    visible_row_range,
 8040                    target_display_point,
 8041                    line_height,
 8042                    scroll_pixel_position,
 8043                    content_origin,
 8044                    editor_width,
 8045                    window,
 8046                    cx,
 8047                )
 8048            }
 8049            InlineCompletion::Edit {
 8050                edits,
 8051                edit_preview,
 8052                display_mode: EditDisplayMode::DiffPopover,
 8053                snapshot,
 8054            } => self.render_edit_prediction_diff_popover(
 8055                text_bounds,
 8056                content_origin,
 8057                right_margin,
 8058                editor_snapshot,
 8059                visible_row_range,
 8060                line_layouts,
 8061                line_height,
 8062                scroll_pixel_position,
 8063                newest_selection_head,
 8064                editor_width,
 8065                style,
 8066                edits,
 8067                edit_preview,
 8068                snapshot,
 8069                window,
 8070                cx,
 8071            ),
 8072        }
 8073    }
 8074
 8075    fn render_edit_prediction_modifier_jump_popover(
 8076        &mut self,
 8077        text_bounds: &Bounds<Pixels>,
 8078        content_origin: gpui::Point<Pixels>,
 8079        visible_row_range: Range<DisplayRow>,
 8080        line_layouts: &[LineWithInvisibles],
 8081        line_height: Pixels,
 8082        scroll_pixel_position: gpui::Point<Pixels>,
 8083        newest_selection_head: Option<DisplayPoint>,
 8084        target_display_point: DisplayPoint,
 8085        window: &mut Window,
 8086        cx: &mut App,
 8087    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8088        let scrolled_content_origin =
 8089            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8090
 8091        const SCROLL_PADDING_Y: Pixels = px(12.);
 8092
 8093        if target_display_point.row() < visible_row_range.start {
 8094            return self.render_edit_prediction_scroll_popover(
 8095                |_| SCROLL_PADDING_Y,
 8096                IconName::ArrowUp,
 8097                visible_row_range,
 8098                line_layouts,
 8099                newest_selection_head,
 8100                scrolled_content_origin,
 8101                window,
 8102                cx,
 8103            );
 8104        } else if target_display_point.row() >= visible_row_range.end {
 8105            return self.render_edit_prediction_scroll_popover(
 8106                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8107                IconName::ArrowDown,
 8108                visible_row_range,
 8109                line_layouts,
 8110                newest_selection_head,
 8111                scrolled_content_origin,
 8112                window,
 8113                cx,
 8114            );
 8115        }
 8116
 8117        const POLE_WIDTH: Pixels = px(2.);
 8118
 8119        let line_layout =
 8120            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8121        let target_column = target_display_point.column() as usize;
 8122
 8123        let target_x = line_layout.x_for_index(target_column);
 8124        let target_y =
 8125            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8126
 8127        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8128
 8129        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8130        border_color.l += 0.001;
 8131
 8132        let mut element = v_flex()
 8133            .items_end()
 8134            .when(flag_on_right, |el| el.items_start())
 8135            .child(if flag_on_right {
 8136                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8137                    .rounded_bl(px(0.))
 8138                    .rounded_tl(px(0.))
 8139                    .border_l_2()
 8140                    .border_color(border_color)
 8141            } else {
 8142                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8143                    .rounded_br(px(0.))
 8144                    .rounded_tr(px(0.))
 8145                    .border_r_2()
 8146                    .border_color(border_color)
 8147            })
 8148            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8149            .into_any();
 8150
 8151        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8152
 8153        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8154            - point(
 8155                if flag_on_right {
 8156                    POLE_WIDTH
 8157                } else {
 8158                    size.width - POLE_WIDTH
 8159                },
 8160                size.height - line_height,
 8161            );
 8162
 8163        origin.x = origin.x.max(content_origin.x);
 8164
 8165        element.prepaint_at(origin, window, cx);
 8166
 8167        Some((element, origin))
 8168    }
 8169
 8170    fn render_edit_prediction_scroll_popover(
 8171        &mut self,
 8172        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8173        scroll_icon: IconName,
 8174        visible_row_range: Range<DisplayRow>,
 8175        line_layouts: &[LineWithInvisibles],
 8176        newest_selection_head: Option<DisplayPoint>,
 8177        scrolled_content_origin: gpui::Point<Pixels>,
 8178        window: &mut Window,
 8179        cx: &mut App,
 8180    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8181        let mut element = self
 8182            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8183            .into_any();
 8184
 8185        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8186
 8187        let cursor = newest_selection_head?;
 8188        let cursor_row_layout =
 8189            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8190        let cursor_column = cursor.column() as usize;
 8191
 8192        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8193
 8194        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8195
 8196        element.prepaint_at(origin, window, cx);
 8197        Some((element, origin))
 8198    }
 8199
 8200    fn render_edit_prediction_eager_jump_popover(
 8201        &mut self,
 8202        text_bounds: &Bounds<Pixels>,
 8203        content_origin: gpui::Point<Pixels>,
 8204        editor_snapshot: &EditorSnapshot,
 8205        visible_row_range: Range<DisplayRow>,
 8206        scroll_top: f32,
 8207        scroll_bottom: f32,
 8208        line_height: Pixels,
 8209        scroll_pixel_position: gpui::Point<Pixels>,
 8210        target_display_point: DisplayPoint,
 8211        editor_width: Pixels,
 8212        window: &mut Window,
 8213        cx: &mut App,
 8214    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8215        if target_display_point.row().as_f32() < scroll_top {
 8216            let mut element = self
 8217                .render_edit_prediction_line_popover(
 8218                    "Jump to Edit",
 8219                    Some(IconName::ArrowUp),
 8220                    window,
 8221                    cx,
 8222                )?
 8223                .into_any();
 8224
 8225            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8226            let offset = point(
 8227                (text_bounds.size.width - size.width) / 2.,
 8228                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8229            );
 8230
 8231            let origin = text_bounds.origin + offset;
 8232            element.prepaint_at(origin, window, cx);
 8233            Some((element, origin))
 8234        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8235            let mut element = self
 8236                .render_edit_prediction_line_popover(
 8237                    "Jump to Edit",
 8238                    Some(IconName::ArrowDown),
 8239                    window,
 8240                    cx,
 8241                )?
 8242                .into_any();
 8243
 8244            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8245            let offset = point(
 8246                (text_bounds.size.width - size.width) / 2.,
 8247                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8248            );
 8249
 8250            let origin = text_bounds.origin + offset;
 8251            element.prepaint_at(origin, window, cx);
 8252            Some((element, origin))
 8253        } else {
 8254            self.render_edit_prediction_end_of_line_popover(
 8255                "Jump to Edit",
 8256                editor_snapshot,
 8257                visible_row_range,
 8258                target_display_point,
 8259                line_height,
 8260                scroll_pixel_position,
 8261                content_origin,
 8262                editor_width,
 8263                window,
 8264                cx,
 8265            )
 8266        }
 8267    }
 8268
 8269    fn render_edit_prediction_end_of_line_popover(
 8270        self: &mut Editor,
 8271        label: &'static str,
 8272        editor_snapshot: &EditorSnapshot,
 8273        visible_row_range: Range<DisplayRow>,
 8274        target_display_point: DisplayPoint,
 8275        line_height: Pixels,
 8276        scroll_pixel_position: gpui::Point<Pixels>,
 8277        content_origin: gpui::Point<Pixels>,
 8278        editor_width: Pixels,
 8279        window: &mut Window,
 8280        cx: &mut App,
 8281    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8282        let target_line_end = DisplayPoint::new(
 8283            target_display_point.row(),
 8284            editor_snapshot.line_len(target_display_point.row()),
 8285        );
 8286
 8287        let mut element = self
 8288            .render_edit_prediction_line_popover(label, None, window, cx)?
 8289            .into_any();
 8290
 8291        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8292
 8293        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8294
 8295        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8296        let mut origin = start_point
 8297            + line_origin
 8298            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8299        origin.x = origin.x.max(content_origin.x);
 8300
 8301        let max_x = content_origin.x + editor_width - size.width;
 8302
 8303        if origin.x > max_x {
 8304            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8305
 8306            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8307                origin.y += offset;
 8308                IconName::ArrowUp
 8309            } else {
 8310                origin.y -= offset;
 8311                IconName::ArrowDown
 8312            };
 8313
 8314            element = self
 8315                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8316                .into_any();
 8317
 8318            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8319
 8320            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8321        }
 8322
 8323        element.prepaint_at(origin, window, cx);
 8324        Some((element, origin))
 8325    }
 8326
 8327    fn render_edit_prediction_diff_popover(
 8328        self: &Editor,
 8329        text_bounds: &Bounds<Pixels>,
 8330        content_origin: gpui::Point<Pixels>,
 8331        right_margin: Pixels,
 8332        editor_snapshot: &EditorSnapshot,
 8333        visible_row_range: Range<DisplayRow>,
 8334        line_layouts: &[LineWithInvisibles],
 8335        line_height: Pixels,
 8336        scroll_pixel_position: gpui::Point<Pixels>,
 8337        newest_selection_head: Option<DisplayPoint>,
 8338        editor_width: Pixels,
 8339        style: &EditorStyle,
 8340        edits: &Vec<(Range<Anchor>, String)>,
 8341        edit_preview: &Option<language::EditPreview>,
 8342        snapshot: &language::BufferSnapshot,
 8343        window: &mut Window,
 8344        cx: &mut App,
 8345    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8346        let edit_start = edits
 8347            .first()
 8348            .unwrap()
 8349            .0
 8350            .start
 8351            .to_display_point(editor_snapshot);
 8352        let edit_end = edits
 8353            .last()
 8354            .unwrap()
 8355            .0
 8356            .end
 8357            .to_display_point(editor_snapshot);
 8358
 8359        let is_visible = visible_row_range.contains(&edit_start.row())
 8360            || visible_row_range.contains(&edit_end.row());
 8361        if !is_visible {
 8362            return None;
 8363        }
 8364
 8365        let highlighted_edits =
 8366            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8367
 8368        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8369        let line_count = highlighted_edits.text.lines().count();
 8370
 8371        const BORDER_WIDTH: Pixels = px(1.);
 8372
 8373        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8374        let has_keybind = keybind.is_some();
 8375
 8376        let mut element = h_flex()
 8377            .items_start()
 8378            .child(
 8379                h_flex()
 8380                    .bg(cx.theme().colors().editor_background)
 8381                    .border(BORDER_WIDTH)
 8382                    .shadow_sm()
 8383                    .border_color(cx.theme().colors().border)
 8384                    .rounded_l_lg()
 8385                    .when(line_count > 1, |el| el.rounded_br_lg())
 8386                    .pr_1()
 8387                    .child(styled_text),
 8388            )
 8389            .child(
 8390                h_flex()
 8391                    .h(line_height + BORDER_WIDTH * 2.)
 8392                    .px_1p5()
 8393                    .gap_1()
 8394                    // Workaround: For some reason, there's a gap if we don't do this
 8395                    .ml(-BORDER_WIDTH)
 8396                    .shadow(vec![gpui::BoxShadow {
 8397                        color: gpui::black().opacity(0.05),
 8398                        offset: point(px(1.), px(1.)),
 8399                        blur_radius: px(2.),
 8400                        spread_radius: px(0.),
 8401                    }])
 8402                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8403                    .border(BORDER_WIDTH)
 8404                    .border_color(cx.theme().colors().border)
 8405                    .rounded_r_lg()
 8406                    .id("edit_prediction_diff_popover_keybind")
 8407                    .when(!has_keybind, |el| {
 8408                        let status_colors = cx.theme().status();
 8409
 8410                        el.bg(status_colors.error_background)
 8411                            .border_color(status_colors.error.opacity(0.6))
 8412                            .child(Icon::new(IconName::Info).color(Color::Error))
 8413                            .cursor_default()
 8414                            .hoverable_tooltip(move |_window, cx| {
 8415                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8416                            })
 8417                    })
 8418                    .children(keybind),
 8419            )
 8420            .into_any();
 8421
 8422        let longest_row =
 8423            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8424        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8425            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8426        } else {
 8427            layout_line(
 8428                longest_row,
 8429                editor_snapshot,
 8430                style,
 8431                editor_width,
 8432                |_| false,
 8433                window,
 8434                cx,
 8435            )
 8436            .width
 8437        };
 8438
 8439        let viewport_bounds =
 8440            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8441                right: -right_margin,
 8442                ..Default::default()
 8443            });
 8444
 8445        let x_after_longest =
 8446            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8447                - scroll_pixel_position.x;
 8448
 8449        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8450
 8451        // Fully visible if it can be displayed within the window (allow overlapping other
 8452        // panes). However, this is only allowed if the popover starts within text_bounds.
 8453        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8454            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8455
 8456        let mut origin = if can_position_to_the_right {
 8457            point(
 8458                x_after_longest,
 8459                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8460                    - scroll_pixel_position.y,
 8461            )
 8462        } else {
 8463            let cursor_row = newest_selection_head.map(|head| head.row());
 8464            let above_edit = edit_start
 8465                .row()
 8466                .0
 8467                .checked_sub(line_count as u32)
 8468                .map(DisplayRow);
 8469            let below_edit = Some(edit_end.row() + 1);
 8470            let above_cursor =
 8471                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8472            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8473
 8474            // Place the edit popover adjacent to the edit if there is a location
 8475            // available that is onscreen and does not obscure the cursor. Otherwise,
 8476            // place it adjacent to the cursor.
 8477            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8478                .into_iter()
 8479                .flatten()
 8480                .find(|&start_row| {
 8481                    let end_row = start_row + line_count as u32;
 8482                    visible_row_range.contains(&start_row)
 8483                        && visible_row_range.contains(&end_row)
 8484                        && cursor_row.map_or(true, |cursor_row| {
 8485                            !((start_row..end_row).contains(&cursor_row))
 8486                        })
 8487                })?;
 8488
 8489            content_origin
 8490                + point(
 8491                    -scroll_pixel_position.x,
 8492                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8493                )
 8494        };
 8495
 8496        origin.x -= BORDER_WIDTH;
 8497
 8498        window.defer_draw(element, origin, 1);
 8499
 8500        // Do not return an element, since it will already be drawn due to defer_draw.
 8501        None
 8502    }
 8503
 8504    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8505        px(30.)
 8506    }
 8507
 8508    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8509        if self.read_only(cx) {
 8510            cx.theme().players().read_only()
 8511        } else {
 8512            self.style.as_ref().unwrap().local_player
 8513        }
 8514    }
 8515
 8516    fn render_edit_prediction_accept_keybind(
 8517        &self,
 8518        window: &mut Window,
 8519        cx: &App,
 8520    ) -> Option<AnyElement> {
 8521        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8522        let accept_keystroke = accept_binding.keystroke()?;
 8523
 8524        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8525
 8526        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8527            Color::Accent
 8528        } else {
 8529            Color::Muted
 8530        };
 8531
 8532        h_flex()
 8533            .px_0p5()
 8534            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8535            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8536            .text_size(TextSize::XSmall.rems(cx))
 8537            .child(h_flex().children(ui::render_modifiers(
 8538                &accept_keystroke.modifiers,
 8539                PlatformStyle::platform(),
 8540                Some(modifiers_color),
 8541                Some(IconSize::XSmall.rems().into()),
 8542                true,
 8543            )))
 8544            .when(is_platform_style_mac, |parent| {
 8545                parent.child(accept_keystroke.key.clone())
 8546            })
 8547            .when(!is_platform_style_mac, |parent| {
 8548                parent.child(
 8549                    Key::new(
 8550                        util::capitalize(&accept_keystroke.key),
 8551                        Some(Color::Default),
 8552                    )
 8553                    .size(Some(IconSize::XSmall.rems().into())),
 8554                )
 8555            })
 8556            .into_any()
 8557            .into()
 8558    }
 8559
 8560    fn render_edit_prediction_line_popover(
 8561        &self,
 8562        label: impl Into<SharedString>,
 8563        icon: Option<IconName>,
 8564        window: &mut Window,
 8565        cx: &App,
 8566    ) -> Option<Stateful<Div>> {
 8567        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8568
 8569        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8570        let has_keybind = keybind.is_some();
 8571
 8572        let result = h_flex()
 8573            .id("ep-line-popover")
 8574            .py_0p5()
 8575            .pl_1()
 8576            .pr(padding_right)
 8577            .gap_1()
 8578            .rounded_md()
 8579            .border_1()
 8580            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8581            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8582            .shadow_sm()
 8583            .when(!has_keybind, |el| {
 8584                let status_colors = cx.theme().status();
 8585
 8586                el.bg(status_colors.error_background)
 8587                    .border_color(status_colors.error.opacity(0.6))
 8588                    .pl_2()
 8589                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8590                    .cursor_default()
 8591                    .hoverable_tooltip(move |_window, cx| {
 8592                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8593                    })
 8594            })
 8595            .children(keybind)
 8596            .child(
 8597                Label::new(label)
 8598                    .size(LabelSize::Small)
 8599                    .when(!has_keybind, |el| {
 8600                        el.color(cx.theme().status().error.into()).strikethrough()
 8601                    }),
 8602            )
 8603            .when(!has_keybind, |el| {
 8604                el.child(
 8605                    h_flex().ml_1().child(
 8606                        Icon::new(IconName::Info)
 8607                            .size(IconSize::Small)
 8608                            .color(cx.theme().status().error.into()),
 8609                    ),
 8610                )
 8611            })
 8612            .when_some(icon, |element, icon| {
 8613                element.child(
 8614                    div()
 8615                        .mt(px(1.5))
 8616                        .child(Icon::new(icon).size(IconSize::Small)),
 8617                )
 8618            });
 8619
 8620        Some(result)
 8621    }
 8622
 8623    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8624        let accent_color = cx.theme().colors().text_accent;
 8625        let editor_bg_color = cx.theme().colors().editor_background;
 8626        editor_bg_color.blend(accent_color.opacity(0.1))
 8627    }
 8628
 8629    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8630        let accent_color = cx.theme().colors().text_accent;
 8631        let editor_bg_color = cx.theme().colors().editor_background;
 8632        editor_bg_color.blend(accent_color.opacity(0.6))
 8633    }
 8634
 8635    fn render_edit_prediction_cursor_popover(
 8636        &self,
 8637        min_width: Pixels,
 8638        max_width: Pixels,
 8639        cursor_point: Point,
 8640        style: &EditorStyle,
 8641        accept_keystroke: Option<&gpui::Keystroke>,
 8642        _window: &Window,
 8643        cx: &mut Context<Editor>,
 8644    ) -> Option<AnyElement> {
 8645        let provider = self.edit_prediction_provider.as_ref()?;
 8646
 8647        if provider.provider.needs_terms_acceptance(cx) {
 8648            return Some(
 8649                h_flex()
 8650                    .min_w(min_width)
 8651                    .flex_1()
 8652                    .px_2()
 8653                    .py_1()
 8654                    .gap_3()
 8655                    .elevation_2(cx)
 8656                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8657                    .id("accept-terms")
 8658                    .cursor_pointer()
 8659                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8660                    .on_click(cx.listener(|this, _event, window, cx| {
 8661                        cx.stop_propagation();
 8662                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8663                        window.dispatch_action(
 8664                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8665                            cx,
 8666                        );
 8667                    }))
 8668                    .child(
 8669                        h_flex()
 8670                            .flex_1()
 8671                            .gap_2()
 8672                            .child(Icon::new(IconName::ZedPredict))
 8673                            .child(Label::new("Accept Terms of Service"))
 8674                            .child(div().w_full())
 8675                            .child(
 8676                                Icon::new(IconName::ArrowUpRight)
 8677                                    .color(Color::Muted)
 8678                                    .size(IconSize::Small),
 8679                            )
 8680                            .into_any_element(),
 8681                    )
 8682                    .into_any(),
 8683            );
 8684        }
 8685
 8686        let is_refreshing = provider.provider.is_refreshing(cx);
 8687
 8688        fn pending_completion_container() -> Div {
 8689            h_flex()
 8690                .h_full()
 8691                .flex_1()
 8692                .gap_2()
 8693                .child(Icon::new(IconName::ZedPredict))
 8694        }
 8695
 8696        let completion = match &self.active_inline_completion {
 8697            Some(prediction) => {
 8698                if !self.has_visible_completions_menu() {
 8699                    const RADIUS: Pixels = px(6.);
 8700                    const BORDER_WIDTH: Pixels = px(1.);
 8701
 8702                    return Some(
 8703                        h_flex()
 8704                            .elevation_2(cx)
 8705                            .border(BORDER_WIDTH)
 8706                            .border_color(cx.theme().colors().border)
 8707                            .when(accept_keystroke.is_none(), |el| {
 8708                                el.border_color(cx.theme().status().error)
 8709                            })
 8710                            .rounded(RADIUS)
 8711                            .rounded_tl(px(0.))
 8712                            .overflow_hidden()
 8713                            .child(div().px_1p5().child(match &prediction.completion {
 8714                                InlineCompletion::Move { target, snapshot } => {
 8715                                    use text::ToPoint as _;
 8716                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8717                                    {
 8718                                        Icon::new(IconName::ZedPredictDown)
 8719                                    } else {
 8720                                        Icon::new(IconName::ZedPredictUp)
 8721                                    }
 8722                                }
 8723                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8724                            }))
 8725                            .child(
 8726                                h_flex()
 8727                                    .gap_1()
 8728                                    .py_1()
 8729                                    .px_2()
 8730                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8731                                    .border_l_1()
 8732                                    .border_color(cx.theme().colors().border)
 8733                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8734                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8735                                        el.child(
 8736                                            Label::new("Hold")
 8737                                                .size(LabelSize::Small)
 8738                                                .when(accept_keystroke.is_none(), |el| {
 8739                                                    el.strikethrough()
 8740                                                })
 8741                                                .line_height_style(LineHeightStyle::UiLabel),
 8742                                        )
 8743                                    })
 8744                                    .id("edit_prediction_cursor_popover_keybind")
 8745                                    .when(accept_keystroke.is_none(), |el| {
 8746                                        let status_colors = cx.theme().status();
 8747
 8748                                        el.bg(status_colors.error_background)
 8749                                            .border_color(status_colors.error.opacity(0.6))
 8750                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8751                                            .cursor_default()
 8752                                            .hoverable_tooltip(move |_window, cx| {
 8753                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8754                                                    .into()
 8755                                            })
 8756                                    })
 8757                                    .when_some(
 8758                                        accept_keystroke.as_ref(),
 8759                                        |el, accept_keystroke| {
 8760                                            el.child(h_flex().children(ui::render_modifiers(
 8761                                                &accept_keystroke.modifiers,
 8762                                                PlatformStyle::platform(),
 8763                                                Some(Color::Default),
 8764                                                Some(IconSize::XSmall.rems().into()),
 8765                                                false,
 8766                                            )))
 8767                                        },
 8768                                    ),
 8769                            )
 8770                            .into_any(),
 8771                    );
 8772                }
 8773
 8774                self.render_edit_prediction_cursor_popover_preview(
 8775                    prediction,
 8776                    cursor_point,
 8777                    style,
 8778                    cx,
 8779                )?
 8780            }
 8781
 8782            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8783                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8784                    stale_completion,
 8785                    cursor_point,
 8786                    style,
 8787                    cx,
 8788                )?,
 8789
 8790                None => {
 8791                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8792                }
 8793            },
 8794
 8795            None => pending_completion_container().child(Label::new("No Prediction")),
 8796        };
 8797
 8798        let completion = if is_refreshing {
 8799            completion
 8800                .with_animation(
 8801                    "loading-completion",
 8802                    Animation::new(Duration::from_secs(2))
 8803                        .repeat()
 8804                        .with_easing(pulsating_between(0.4, 0.8)),
 8805                    |label, delta| label.opacity(delta),
 8806                )
 8807                .into_any_element()
 8808        } else {
 8809            completion.into_any_element()
 8810        };
 8811
 8812        let has_completion = self.active_inline_completion.is_some();
 8813
 8814        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8815        Some(
 8816            h_flex()
 8817                .min_w(min_width)
 8818                .max_w(max_width)
 8819                .flex_1()
 8820                .elevation_2(cx)
 8821                .border_color(cx.theme().colors().border)
 8822                .child(
 8823                    div()
 8824                        .flex_1()
 8825                        .py_1()
 8826                        .px_2()
 8827                        .overflow_hidden()
 8828                        .child(completion),
 8829                )
 8830                .when_some(accept_keystroke, |el, accept_keystroke| {
 8831                    if !accept_keystroke.modifiers.modified() {
 8832                        return el;
 8833                    }
 8834
 8835                    el.child(
 8836                        h_flex()
 8837                            .h_full()
 8838                            .border_l_1()
 8839                            .rounded_r_lg()
 8840                            .border_color(cx.theme().colors().border)
 8841                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8842                            .gap_1()
 8843                            .py_1()
 8844                            .px_2()
 8845                            .child(
 8846                                h_flex()
 8847                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8848                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8849                                    .child(h_flex().children(ui::render_modifiers(
 8850                                        &accept_keystroke.modifiers,
 8851                                        PlatformStyle::platform(),
 8852                                        Some(if !has_completion {
 8853                                            Color::Muted
 8854                                        } else {
 8855                                            Color::Default
 8856                                        }),
 8857                                        None,
 8858                                        false,
 8859                                    ))),
 8860                            )
 8861                            .child(Label::new("Preview").into_any_element())
 8862                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8863                    )
 8864                })
 8865                .into_any(),
 8866        )
 8867    }
 8868
 8869    fn render_edit_prediction_cursor_popover_preview(
 8870        &self,
 8871        completion: &InlineCompletionState,
 8872        cursor_point: Point,
 8873        style: &EditorStyle,
 8874        cx: &mut Context<Editor>,
 8875    ) -> Option<Div> {
 8876        use text::ToPoint as _;
 8877
 8878        fn render_relative_row_jump(
 8879            prefix: impl Into<String>,
 8880            current_row: u32,
 8881            target_row: u32,
 8882        ) -> Div {
 8883            let (row_diff, arrow) = if target_row < current_row {
 8884                (current_row - target_row, IconName::ArrowUp)
 8885            } else {
 8886                (target_row - current_row, IconName::ArrowDown)
 8887            };
 8888
 8889            h_flex()
 8890                .child(
 8891                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8892                        .color(Color::Muted)
 8893                        .size(LabelSize::Small),
 8894                )
 8895                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8896        }
 8897
 8898        match &completion.completion {
 8899            InlineCompletion::Move {
 8900                target, snapshot, ..
 8901            } => Some(
 8902                h_flex()
 8903                    .px_2()
 8904                    .gap_2()
 8905                    .flex_1()
 8906                    .child(
 8907                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8908                            Icon::new(IconName::ZedPredictDown)
 8909                        } else {
 8910                            Icon::new(IconName::ZedPredictUp)
 8911                        },
 8912                    )
 8913                    .child(Label::new("Jump to Edit")),
 8914            ),
 8915
 8916            InlineCompletion::Edit {
 8917                edits,
 8918                edit_preview,
 8919                snapshot,
 8920                display_mode: _,
 8921            } => {
 8922                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8923
 8924                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8925                    &snapshot,
 8926                    &edits,
 8927                    edit_preview.as_ref()?,
 8928                    true,
 8929                    cx,
 8930                )
 8931                .first_line_preview();
 8932
 8933                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8934                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8935
 8936                let preview = h_flex()
 8937                    .gap_1()
 8938                    .min_w_16()
 8939                    .child(styled_text)
 8940                    .when(has_more_lines, |parent| parent.child(""));
 8941
 8942                let left = if first_edit_row != cursor_point.row {
 8943                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8944                        .into_any_element()
 8945                } else {
 8946                    Icon::new(IconName::ZedPredict).into_any_element()
 8947                };
 8948
 8949                Some(
 8950                    h_flex()
 8951                        .h_full()
 8952                        .flex_1()
 8953                        .gap_2()
 8954                        .pr_1()
 8955                        .overflow_x_hidden()
 8956                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8957                        .child(left)
 8958                        .child(preview),
 8959                )
 8960            }
 8961        }
 8962    }
 8963
 8964    pub fn render_context_menu(
 8965        &self,
 8966        style: &EditorStyle,
 8967        max_height_in_lines: u32,
 8968        window: &mut Window,
 8969        cx: &mut Context<Editor>,
 8970    ) -> Option<AnyElement> {
 8971        let menu = self.context_menu.borrow();
 8972        let menu = menu.as_ref()?;
 8973        if !menu.visible() {
 8974            return None;
 8975        };
 8976        Some(menu.render(style, max_height_in_lines, window, cx))
 8977    }
 8978
 8979    fn render_context_menu_aside(
 8980        &mut self,
 8981        max_size: Size<Pixels>,
 8982        window: &mut Window,
 8983        cx: &mut Context<Editor>,
 8984    ) -> Option<AnyElement> {
 8985        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8986            if menu.visible() {
 8987                menu.render_aside(max_size, window, cx)
 8988            } else {
 8989                None
 8990            }
 8991        })
 8992    }
 8993
 8994    fn hide_context_menu(
 8995        &mut self,
 8996        window: &mut Window,
 8997        cx: &mut Context<Self>,
 8998    ) -> Option<CodeContextMenu> {
 8999        cx.notify();
 9000        self.completion_tasks.clear();
 9001        let context_menu = self.context_menu.borrow_mut().take();
 9002        self.stale_inline_completion_in_menu.take();
 9003        self.update_visible_inline_completion(window, cx);
 9004        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9005            if let Some(completion_provider) = &self.completion_provider {
 9006                completion_provider.selection_changed(None, window, cx);
 9007            }
 9008        }
 9009        context_menu
 9010    }
 9011
 9012    fn show_snippet_choices(
 9013        &mut self,
 9014        choices: &Vec<String>,
 9015        selection: Range<Anchor>,
 9016        cx: &mut Context<Self>,
 9017    ) {
 9018        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9019            (Some(a), Some(b)) if a == b => a,
 9020            _ => {
 9021                log::error!("expected anchor range to have matching buffer IDs");
 9022                return;
 9023            }
 9024        };
 9025        let multi_buffer = self.buffer().read(cx);
 9026        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9027            return;
 9028        };
 9029
 9030        let id = post_inc(&mut self.next_completion_id);
 9031        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9032        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9033            CompletionsMenu::new_snippet_choices(
 9034                id,
 9035                true,
 9036                choices,
 9037                selection,
 9038                buffer,
 9039                snippet_sort_order,
 9040            ),
 9041        ));
 9042    }
 9043
 9044    pub fn insert_snippet(
 9045        &mut self,
 9046        insertion_ranges: &[Range<usize>],
 9047        snippet: Snippet,
 9048        window: &mut Window,
 9049        cx: &mut Context<Self>,
 9050    ) -> Result<()> {
 9051        struct Tabstop<T> {
 9052            is_end_tabstop: bool,
 9053            ranges: Vec<Range<T>>,
 9054            choices: Option<Vec<String>>,
 9055        }
 9056
 9057        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9058            let snippet_text: Arc<str> = snippet.text.clone().into();
 9059            let edits = insertion_ranges
 9060                .iter()
 9061                .cloned()
 9062                .map(|range| (range, snippet_text.clone()));
 9063            let autoindent_mode = AutoindentMode::Block {
 9064                original_indent_columns: Vec::new(),
 9065            };
 9066            buffer.edit(edits, Some(autoindent_mode), cx);
 9067
 9068            let snapshot = &*buffer.read(cx);
 9069            let snippet = &snippet;
 9070            snippet
 9071                .tabstops
 9072                .iter()
 9073                .map(|tabstop| {
 9074                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9075                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9076                    });
 9077                    let mut tabstop_ranges = tabstop
 9078                        .ranges
 9079                        .iter()
 9080                        .flat_map(|tabstop_range| {
 9081                            let mut delta = 0_isize;
 9082                            insertion_ranges.iter().map(move |insertion_range| {
 9083                                let insertion_start = insertion_range.start as isize + delta;
 9084                                delta +=
 9085                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9086
 9087                                let start = ((insertion_start + tabstop_range.start) as usize)
 9088                                    .min(snapshot.len());
 9089                                let end = ((insertion_start + tabstop_range.end) as usize)
 9090                                    .min(snapshot.len());
 9091                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9092                            })
 9093                        })
 9094                        .collect::<Vec<_>>();
 9095                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9096
 9097                    Tabstop {
 9098                        is_end_tabstop,
 9099                        ranges: tabstop_ranges,
 9100                        choices: tabstop.choices.clone(),
 9101                    }
 9102                })
 9103                .collect::<Vec<_>>()
 9104        });
 9105        if let Some(tabstop) = tabstops.first() {
 9106            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9107                // Reverse order so that the first range is the newest created selection.
 9108                // Completions will use it and autoscroll will prioritize it.
 9109                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9110            });
 9111
 9112            if let Some(choices) = &tabstop.choices {
 9113                if let Some(selection) = tabstop.ranges.first() {
 9114                    self.show_snippet_choices(choices, selection.clone(), cx)
 9115                }
 9116            }
 9117
 9118            // If we're already at the last tabstop and it's at the end of the snippet,
 9119            // we're done, we don't need to keep the state around.
 9120            if !tabstop.is_end_tabstop {
 9121                let choices = tabstops
 9122                    .iter()
 9123                    .map(|tabstop| tabstop.choices.clone())
 9124                    .collect();
 9125
 9126                let ranges = tabstops
 9127                    .into_iter()
 9128                    .map(|tabstop| tabstop.ranges)
 9129                    .collect::<Vec<_>>();
 9130
 9131                self.snippet_stack.push(SnippetState {
 9132                    active_index: 0,
 9133                    ranges,
 9134                    choices,
 9135                });
 9136            }
 9137
 9138            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9139            if self.autoclose_regions.is_empty() {
 9140                let snapshot = self.buffer.read(cx).snapshot(cx);
 9141                for selection in &mut self.selections.all::<Point>(cx) {
 9142                    let selection_head = selection.head();
 9143                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9144                        continue;
 9145                    };
 9146
 9147                    let mut bracket_pair = None;
 9148                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9149                    let prev_chars = snapshot
 9150                        .reversed_chars_at(selection_head)
 9151                        .collect::<String>();
 9152                    for (pair, enabled) in scope.brackets() {
 9153                        if enabled
 9154                            && pair.close
 9155                            && prev_chars.starts_with(pair.start.as_str())
 9156                            && next_chars.starts_with(pair.end.as_str())
 9157                        {
 9158                            bracket_pair = Some(pair.clone());
 9159                            break;
 9160                        }
 9161                    }
 9162                    if let Some(pair) = bracket_pair {
 9163                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9164                        let autoclose_enabled =
 9165                            self.use_autoclose && snapshot_settings.use_autoclose;
 9166                        if autoclose_enabled {
 9167                            let start = snapshot.anchor_after(selection_head);
 9168                            let end = snapshot.anchor_after(selection_head);
 9169                            self.autoclose_regions.push(AutocloseRegion {
 9170                                selection_id: selection.id,
 9171                                range: start..end,
 9172                                pair,
 9173                            });
 9174                        }
 9175                    }
 9176                }
 9177            }
 9178        }
 9179        Ok(())
 9180    }
 9181
 9182    pub fn move_to_next_snippet_tabstop(
 9183        &mut self,
 9184        window: &mut Window,
 9185        cx: &mut Context<Self>,
 9186    ) -> bool {
 9187        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9188    }
 9189
 9190    pub fn move_to_prev_snippet_tabstop(
 9191        &mut self,
 9192        window: &mut Window,
 9193        cx: &mut Context<Self>,
 9194    ) -> bool {
 9195        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9196    }
 9197
 9198    pub fn move_to_snippet_tabstop(
 9199        &mut self,
 9200        bias: Bias,
 9201        window: &mut Window,
 9202        cx: &mut Context<Self>,
 9203    ) -> bool {
 9204        if let Some(mut snippet) = self.snippet_stack.pop() {
 9205            match bias {
 9206                Bias::Left => {
 9207                    if snippet.active_index > 0 {
 9208                        snippet.active_index -= 1;
 9209                    } else {
 9210                        self.snippet_stack.push(snippet);
 9211                        return false;
 9212                    }
 9213                }
 9214                Bias::Right => {
 9215                    if snippet.active_index + 1 < snippet.ranges.len() {
 9216                        snippet.active_index += 1;
 9217                    } else {
 9218                        self.snippet_stack.push(snippet);
 9219                        return false;
 9220                    }
 9221                }
 9222            }
 9223            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9224                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9225                    // Reverse order so that the first range is the newest created selection.
 9226                    // Completions will use it and autoscroll will prioritize it.
 9227                    s.select_ranges(current_ranges.iter().rev().cloned())
 9228                });
 9229
 9230                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9231                    if let Some(selection) = current_ranges.first() {
 9232                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9233                    }
 9234                }
 9235
 9236                // If snippet state is not at the last tabstop, push it back on the stack
 9237                if snippet.active_index + 1 < snippet.ranges.len() {
 9238                    self.snippet_stack.push(snippet);
 9239                }
 9240                return true;
 9241            }
 9242        }
 9243
 9244        false
 9245    }
 9246
 9247    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9248        self.transact(window, cx, |this, window, cx| {
 9249            this.select_all(&SelectAll, window, cx);
 9250            this.insert("", window, cx);
 9251        });
 9252    }
 9253
 9254    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9255        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9256        self.transact(window, cx, |this, window, cx| {
 9257            this.select_autoclose_pair(window, cx);
 9258            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9259            if !this.linked_edit_ranges.is_empty() {
 9260                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9261                let snapshot = this.buffer.read(cx).snapshot(cx);
 9262
 9263                for selection in selections.iter() {
 9264                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9265                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9266                    if selection_start.buffer_id != selection_end.buffer_id {
 9267                        continue;
 9268                    }
 9269                    if let Some(ranges) =
 9270                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9271                    {
 9272                        for (buffer, entries) in ranges {
 9273                            linked_ranges.entry(buffer).or_default().extend(entries);
 9274                        }
 9275                    }
 9276                }
 9277            }
 9278
 9279            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9280            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9281            for selection in &mut selections {
 9282                if selection.is_empty() {
 9283                    let old_head = selection.head();
 9284                    let mut new_head =
 9285                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9286                            .to_point(&display_map);
 9287                    if let Some((buffer, line_buffer_range)) = display_map
 9288                        .buffer_snapshot
 9289                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9290                    {
 9291                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9292                        let indent_len = match indent_size.kind {
 9293                            IndentKind::Space => {
 9294                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9295                            }
 9296                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9297                        };
 9298                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9299                            let indent_len = indent_len.get();
 9300                            new_head = cmp::min(
 9301                                new_head,
 9302                                MultiBufferPoint::new(
 9303                                    old_head.row,
 9304                                    ((old_head.column - 1) / indent_len) * indent_len,
 9305                                ),
 9306                            );
 9307                        }
 9308                    }
 9309
 9310                    selection.set_head(new_head, SelectionGoal::None);
 9311                }
 9312            }
 9313
 9314            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9315                s.select(selections)
 9316            });
 9317            this.insert("", window, cx);
 9318            let empty_str: Arc<str> = Arc::from("");
 9319            for (buffer, edits) in linked_ranges {
 9320                let snapshot = buffer.read(cx).snapshot();
 9321                use text::ToPoint as TP;
 9322
 9323                let edits = edits
 9324                    .into_iter()
 9325                    .map(|range| {
 9326                        let end_point = TP::to_point(&range.end, &snapshot);
 9327                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9328
 9329                        if end_point == start_point {
 9330                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9331                                .saturating_sub(1);
 9332                            start_point =
 9333                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9334                        };
 9335
 9336                        (start_point..end_point, empty_str.clone())
 9337                    })
 9338                    .sorted_by_key(|(range, _)| range.start)
 9339                    .collect::<Vec<_>>();
 9340                buffer.update(cx, |this, cx| {
 9341                    this.edit(edits, None, cx);
 9342                })
 9343            }
 9344            this.refresh_inline_completion(true, false, window, cx);
 9345            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9346        });
 9347    }
 9348
 9349    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9350        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9351        self.transact(window, cx, |this, window, cx| {
 9352            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9353                s.move_with(|map, selection| {
 9354                    if selection.is_empty() {
 9355                        let cursor = movement::right(map, selection.head());
 9356                        selection.end = cursor;
 9357                        selection.reversed = true;
 9358                        selection.goal = SelectionGoal::None;
 9359                    }
 9360                })
 9361            });
 9362            this.insert("", window, cx);
 9363            this.refresh_inline_completion(true, false, window, cx);
 9364        });
 9365    }
 9366
 9367    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9368        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9369        if self.move_to_prev_snippet_tabstop(window, cx) {
 9370            return;
 9371        }
 9372        self.outdent(&Outdent, window, cx);
 9373    }
 9374
 9375    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9376        if self.move_to_next_snippet_tabstop(window, cx) {
 9377            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9378            return;
 9379        }
 9380        if self.read_only(cx) {
 9381            return;
 9382        }
 9383        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9384        let mut selections = self.selections.all_adjusted(cx);
 9385        let buffer = self.buffer.read(cx);
 9386        let snapshot = buffer.snapshot(cx);
 9387        let rows_iter = selections.iter().map(|s| s.head().row);
 9388        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9389
 9390        let has_some_cursor_in_whitespace = selections
 9391            .iter()
 9392            .filter(|selection| selection.is_empty())
 9393            .any(|selection| {
 9394                let cursor = selection.head();
 9395                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9396                cursor.column < current_indent.len
 9397            });
 9398
 9399        let mut edits = Vec::new();
 9400        let mut prev_edited_row = 0;
 9401        let mut row_delta = 0;
 9402        for selection in &mut selections {
 9403            if selection.start.row != prev_edited_row {
 9404                row_delta = 0;
 9405            }
 9406            prev_edited_row = selection.end.row;
 9407
 9408            // If the selection is non-empty, then increase the indentation of the selected lines.
 9409            if !selection.is_empty() {
 9410                row_delta =
 9411                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9412                continue;
 9413            }
 9414
 9415            let cursor = selection.head();
 9416            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9417            if let Some(suggested_indent) =
 9418                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9419            {
 9420                // Don't do anything if already at suggested indent
 9421                // and there is any other cursor which is not
 9422                if has_some_cursor_in_whitespace
 9423                    && cursor.column == current_indent.len
 9424                    && current_indent.len == suggested_indent.len
 9425                {
 9426                    continue;
 9427                }
 9428
 9429                // Adjust line and move cursor to suggested indent
 9430                // if cursor is not at suggested indent
 9431                if cursor.column < suggested_indent.len
 9432                    && cursor.column <= current_indent.len
 9433                    && current_indent.len <= suggested_indent.len
 9434                {
 9435                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9436                    selection.end = selection.start;
 9437                    if row_delta == 0 {
 9438                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9439                            cursor.row,
 9440                            current_indent,
 9441                            suggested_indent,
 9442                        ));
 9443                        row_delta = suggested_indent.len - current_indent.len;
 9444                    }
 9445                    continue;
 9446                }
 9447
 9448                // If current indent is more than suggested indent
 9449                // only move cursor to current indent and skip indent
 9450                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9451                    selection.start = Point::new(cursor.row, current_indent.len);
 9452                    selection.end = selection.start;
 9453                    continue;
 9454                }
 9455            }
 9456
 9457            // Otherwise, insert a hard or soft tab.
 9458            let settings = buffer.language_settings_at(cursor, cx);
 9459            let tab_size = if settings.hard_tabs {
 9460                IndentSize::tab()
 9461            } else {
 9462                let tab_size = settings.tab_size.get();
 9463                let indent_remainder = snapshot
 9464                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9465                    .flat_map(str::chars)
 9466                    .fold(row_delta % tab_size, |counter: u32, c| {
 9467                        if c == '\t' {
 9468                            0
 9469                        } else {
 9470                            (counter + 1) % tab_size
 9471                        }
 9472                    });
 9473
 9474                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9475                IndentSize::spaces(chars_to_next_tab_stop)
 9476            };
 9477            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9478            selection.end = selection.start;
 9479            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9480            row_delta += tab_size.len;
 9481        }
 9482
 9483        self.transact(window, cx, |this, window, cx| {
 9484            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9485            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9486                s.select(selections)
 9487            });
 9488            this.refresh_inline_completion(true, false, window, cx);
 9489        });
 9490    }
 9491
 9492    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9493        if self.read_only(cx) {
 9494            return;
 9495        }
 9496        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9497        let mut selections = self.selections.all::<Point>(cx);
 9498        let mut prev_edited_row = 0;
 9499        let mut row_delta = 0;
 9500        let mut edits = Vec::new();
 9501        let buffer = self.buffer.read(cx);
 9502        let snapshot = buffer.snapshot(cx);
 9503        for selection in &mut selections {
 9504            if selection.start.row != prev_edited_row {
 9505                row_delta = 0;
 9506            }
 9507            prev_edited_row = selection.end.row;
 9508
 9509            row_delta =
 9510                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9511        }
 9512
 9513        self.transact(window, cx, |this, window, cx| {
 9514            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9515            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9516                s.select(selections)
 9517            });
 9518        });
 9519    }
 9520
 9521    fn indent_selection(
 9522        buffer: &MultiBuffer,
 9523        snapshot: &MultiBufferSnapshot,
 9524        selection: &mut Selection<Point>,
 9525        edits: &mut Vec<(Range<Point>, String)>,
 9526        delta_for_start_row: u32,
 9527        cx: &App,
 9528    ) -> u32 {
 9529        let settings = buffer.language_settings_at(selection.start, cx);
 9530        let tab_size = settings.tab_size.get();
 9531        let indent_kind = if settings.hard_tabs {
 9532            IndentKind::Tab
 9533        } else {
 9534            IndentKind::Space
 9535        };
 9536        let mut start_row = selection.start.row;
 9537        let mut end_row = selection.end.row + 1;
 9538
 9539        // If a selection ends at the beginning of a line, don't indent
 9540        // that last line.
 9541        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9542            end_row -= 1;
 9543        }
 9544
 9545        // Avoid re-indenting a row that has already been indented by a
 9546        // previous selection, but still update this selection's column
 9547        // to reflect that indentation.
 9548        if delta_for_start_row > 0 {
 9549            start_row += 1;
 9550            selection.start.column += delta_for_start_row;
 9551            if selection.end.row == selection.start.row {
 9552                selection.end.column += delta_for_start_row;
 9553            }
 9554        }
 9555
 9556        let mut delta_for_end_row = 0;
 9557        let has_multiple_rows = start_row + 1 != end_row;
 9558        for row in start_row..end_row {
 9559            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9560            let indent_delta = match (current_indent.kind, indent_kind) {
 9561                (IndentKind::Space, IndentKind::Space) => {
 9562                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9563                    IndentSize::spaces(columns_to_next_tab_stop)
 9564                }
 9565                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9566                (_, IndentKind::Tab) => IndentSize::tab(),
 9567            };
 9568
 9569            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9570                0
 9571            } else {
 9572                selection.start.column
 9573            };
 9574            let row_start = Point::new(row, start);
 9575            edits.push((
 9576                row_start..row_start,
 9577                indent_delta.chars().collect::<String>(),
 9578            ));
 9579
 9580            // Update this selection's endpoints to reflect the indentation.
 9581            if row == selection.start.row {
 9582                selection.start.column += indent_delta.len;
 9583            }
 9584            if row == selection.end.row {
 9585                selection.end.column += indent_delta.len;
 9586                delta_for_end_row = indent_delta.len;
 9587            }
 9588        }
 9589
 9590        if selection.start.row == selection.end.row {
 9591            delta_for_start_row + delta_for_end_row
 9592        } else {
 9593            delta_for_end_row
 9594        }
 9595    }
 9596
 9597    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9598        if self.read_only(cx) {
 9599            return;
 9600        }
 9601        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9602        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9603        let selections = self.selections.all::<Point>(cx);
 9604        let mut deletion_ranges = Vec::new();
 9605        let mut last_outdent = None;
 9606        {
 9607            let buffer = self.buffer.read(cx);
 9608            let snapshot = buffer.snapshot(cx);
 9609            for selection in &selections {
 9610                let settings = buffer.language_settings_at(selection.start, cx);
 9611                let tab_size = settings.tab_size.get();
 9612                let mut rows = selection.spanned_rows(false, &display_map);
 9613
 9614                // Avoid re-outdenting a row that has already been outdented by a
 9615                // previous selection.
 9616                if let Some(last_row) = last_outdent {
 9617                    if last_row == rows.start {
 9618                        rows.start = rows.start.next_row();
 9619                    }
 9620                }
 9621                let has_multiple_rows = rows.len() > 1;
 9622                for row in rows.iter_rows() {
 9623                    let indent_size = snapshot.indent_size_for_line(row);
 9624                    if indent_size.len > 0 {
 9625                        let deletion_len = match indent_size.kind {
 9626                            IndentKind::Space => {
 9627                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9628                                if columns_to_prev_tab_stop == 0 {
 9629                                    tab_size
 9630                                } else {
 9631                                    columns_to_prev_tab_stop
 9632                                }
 9633                            }
 9634                            IndentKind::Tab => 1,
 9635                        };
 9636                        let start = if has_multiple_rows
 9637                            || deletion_len > selection.start.column
 9638                            || indent_size.len < selection.start.column
 9639                        {
 9640                            0
 9641                        } else {
 9642                            selection.start.column - deletion_len
 9643                        };
 9644                        deletion_ranges.push(
 9645                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9646                        );
 9647                        last_outdent = Some(row);
 9648                    }
 9649                }
 9650            }
 9651        }
 9652
 9653        self.transact(window, cx, |this, window, cx| {
 9654            this.buffer.update(cx, |buffer, cx| {
 9655                let empty_str: Arc<str> = Arc::default();
 9656                buffer.edit(
 9657                    deletion_ranges
 9658                        .into_iter()
 9659                        .map(|range| (range, empty_str.clone())),
 9660                    None,
 9661                    cx,
 9662                );
 9663            });
 9664            let selections = this.selections.all::<usize>(cx);
 9665            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9666                s.select(selections)
 9667            });
 9668        });
 9669    }
 9670
 9671    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9672        if self.read_only(cx) {
 9673            return;
 9674        }
 9675        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9676        let selections = self
 9677            .selections
 9678            .all::<usize>(cx)
 9679            .into_iter()
 9680            .map(|s| s.range());
 9681
 9682        self.transact(window, cx, |this, window, cx| {
 9683            this.buffer.update(cx, |buffer, cx| {
 9684                buffer.autoindent_ranges(selections, cx);
 9685            });
 9686            let selections = this.selections.all::<usize>(cx);
 9687            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9688                s.select(selections)
 9689            });
 9690        });
 9691    }
 9692
 9693    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9694        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9696        let selections = self.selections.all::<Point>(cx);
 9697
 9698        let mut new_cursors = Vec::new();
 9699        let mut edit_ranges = Vec::new();
 9700        let mut selections = selections.iter().peekable();
 9701        while let Some(selection) = selections.next() {
 9702            let mut rows = selection.spanned_rows(false, &display_map);
 9703            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9704
 9705            // Accumulate contiguous regions of rows that we want to delete.
 9706            while let Some(next_selection) = selections.peek() {
 9707                let next_rows = next_selection.spanned_rows(false, &display_map);
 9708                if next_rows.start <= rows.end {
 9709                    rows.end = next_rows.end;
 9710                    selections.next().unwrap();
 9711                } else {
 9712                    break;
 9713                }
 9714            }
 9715
 9716            let buffer = &display_map.buffer_snapshot;
 9717            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9718            let edit_end;
 9719            let cursor_buffer_row;
 9720            if buffer.max_point().row >= rows.end.0 {
 9721                // If there's a line after the range, delete the \n from the end of the row range
 9722                // and position the cursor on the next line.
 9723                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9724                cursor_buffer_row = rows.end;
 9725            } else {
 9726                // If there isn't a line after the range, delete the \n from the line before the
 9727                // start of the row range and position the cursor there.
 9728                edit_start = edit_start.saturating_sub(1);
 9729                edit_end = buffer.len();
 9730                cursor_buffer_row = rows.start.previous_row();
 9731            }
 9732
 9733            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9734            *cursor.column_mut() =
 9735                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9736
 9737            new_cursors.push((
 9738                selection.id,
 9739                buffer.anchor_after(cursor.to_point(&display_map)),
 9740            ));
 9741            edit_ranges.push(edit_start..edit_end);
 9742        }
 9743
 9744        self.transact(window, cx, |this, window, cx| {
 9745            let buffer = this.buffer.update(cx, |buffer, cx| {
 9746                let empty_str: Arc<str> = Arc::default();
 9747                buffer.edit(
 9748                    edit_ranges
 9749                        .into_iter()
 9750                        .map(|range| (range, empty_str.clone())),
 9751                    None,
 9752                    cx,
 9753                );
 9754                buffer.snapshot(cx)
 9755            });
 9756            let new_selections = new_cursors
 9757                .into_iter()
 9758                .map(|(id, cursor)| {
 9759                    let cursor = cursor.to_point(&buffer);
 9760                    Selection {
 9761                        id,
 9762                        start: cursor,
 9763                        end: cursor,
 9764                        reversed: false,
 9765                        goal: SelectionGoal::None,
 9766                    }
 9767                })
 9768                .collect();
 9769
 9770            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9771                s.select(new_selections);
 9772            });
 9773        });
 9774    }
 9775
 9776    pub fn join_lines_impl(
 9777        &mut self,
 9778        insert_whitespace: bool,
 9779        window: &mut Window,
 9780        cx: &mut Context<Self>,
 9781    ) {
 9782        if self.read_only(cx) {
 9783            return;
 9784        }
 9785        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9786        for selection in self.selections.all::<Point>(cx) {
 9787            let start = MultiBufferRow(selection.start.row);
 9788            // Treat single line selections as if they include the next line. Otherwise this action
 9789            // would do nothing for single line selections individual cursors.
 9790            let end = if selection.start.row == selection.end.row {
 9791                MultiBufferRow(selection.start.row + 1)
 9792            } else {
 9793                MultiBufferRow(selection.end.row)
 9794            };
 9795
 9796            if let Some(last_row_range) = row_ranges.last_mut() {
 9797                if start <= last_row_range.end {
 9798                    last_row_range.end = end;
 9799                    continue;
 9800                }
 9801            }
 9802            row_ranges.push(start..end);
 9803        }
 9804
 9805        let snapshot = self.buffer.read(cx).snapshot(cx);
 9806        let mut cursor_positions = Vec::new();
 9807        for row_range in &row_ranges {
 9808            let anchor = snapshot.anchor_before(Point::new(
 9809                row_range.end.previous_row().0,
 9810                snapshot.line_len(row_range.end.previous_row()),
 9811            ));
 9812            cursor_positions.push(anchor..anchor);
 9813        }
 9814
 9815        self.transact(window, cx, |this, window, cx| {
 9816            for row_range in row_ranges.into_iter().rev() {
 9817                for row in row_range.iter_rows().rev() {
 9818                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9819                    let next_line_row = row.next_row();
 9820                    let indent = snapshot.indent_size_for_line(next_line_row);
 9821                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9822
 9823                    let replace =
 9824                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9825                            " "
 9826                        } else {
 9827                            ""
 9828                        };
 9829
 9830                    this.buffer.update(cx, |buffer, cx| {
 9831                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9832                    });
 9833                }
 9834            }
 9835
 9836            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9837                s.select_anchor_ranges(cursor_positions)
 9838            });
 9839        });
 9840    }
 9841
 9842    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9843        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9844        self.join_lines_impl(true, window, cx);
 9845    }
 9846
 9847    pub fn sort_lines_case_sensitive(
 9848        &mut self,
 9849        _: &SortLinesCaseSensitive,
 9850        window: &mut Window,
 9851        cx: &mut Context<Self>,
 9852    ) {
 9853        self.manipulate_lines(window, cx, |lines| lines.sort())
 9854    }
 9855
 9856    pub fn sort_lines_case_insensitive(
 9857        &mut self,
 9858        _: &SortLinesCaseInsensitive,
 9859        window: &mut Window,
 9860        cx: &mut Context<Self>,
 9861    ) {
 9862        self.manipulate_lines(window, cx, |lines| {
 9863            lines.sort_by_key(|line| line.to_lowercase())
 9864        })
 9865    }
 9866
 9867    pub fn unique_lines_case_insensitive(
 9868        &mut self,
 9869        _: &UniqueLinesCaseInsensitive,
 9870        window: &mut Window,
 9871        cx: &mut Context<Self>,
 9872    ) {
 9873        self.manipulate_lines(window, cx, |lines| {
 9874            let mut seen = HashSet::default();
 9875            lines.retain(|line| seen.insert(line.to_lowercase()));
 9876        })
 9877    }
 9878
 9879    pub fn unique_lines_case_sensitive(
 9880        &mut self,
 9881        _: &UniqueLinesCaseSensitive,
 9882        window: &mut Window,
 9883        cx: &mut Context<Self>,
 9884    ) {
 9885        self.manipulate_lines(window, cx, |lines| {
 9886            let mut seen = HashSet::default();
 9887            lines.retain(|line| seen.insert(*line));
 9888        })
 9889    }
 9890
 9891    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9892        let Some(project) = self.project.clone() else {
 9893            return;
 9894        };
 9895        self.reload(project, window, cx)
 9896            .detach_and_notify_err(window, cx);
 9897    }
 9898
 9899    pub fn restore_file(
 9900        &mut self,
 9901        _: &::git::RestoreFile,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904    ) {
 9905        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9906        let mut buffer_ids = HashSet::default();
 9907        let snapshot = self.buffer().read(cx).snapshot(cx);
 9908        for selection in self.selections.all::<usize>(cx) {
 9909            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9910        }
 9911
 9912        let buffer = self.buffer().read(cx);
 9913        let ranges = buffer_ids
 9914            .into_iter()
 9915            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9916            .collect::<Vec<_>>();
 9917
 9918        self.restore_hunks_in_ranges(ranges, window, cx);
 9919    }
 9920
 9921    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9922        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9923        let selections = self
 9924            .selections
 9925            .all(cx)
 9926            .into_iter()
 9927            .map(|s| s.range())
 9928            .collect();
 9929        self.restore_hunks_in_ranges(selections, window, cx);
 9930    }
 9931
 9932    pub fn restore_hunks_in_ranges(
 9933        &mut self,
 9934        ranges: Vec<Range<Point>>,
 9935        window: &mut Window,
 9936        cx: &mut Context<Editor>,
 9937    ) {
 9938        let mut revert_changes = HashMap::default();
 9939        let chunk_by = self
 9940            .snapshot(window, cx)
 9941            .hunks_for_ranges(ranges)
 9942            .into_iter()
 9943            .chunk_by(|hunk| hunk.buffer_id);
 9944        for (buffer_id, hunks) in &chunk_by {
 9945            let hunks = hunks.collect::<Vec<_>>();
 9946            for hunk in &hunks {
 9947                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9948            }
 9949            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9950        }
 9951        drop(chunk_by);
 9952        if !revert_changes.is_empty() {
 9953            self.transact(window, cx, |editor, window, cx| {
 9954                editor.restore(revert_changes, window, cx);
 9955            });
 9956        }
 9957    }
 9958
 9959    pub fn open_active_item_in_terminal(
 9960        &mut self,
 9961        _: &OpenInTerminal,
 9962        window: &mut Window,
 9963        cx: &mut Context<Self>,
 9964    ) {
 9965        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9966            let project_path = buffer.read(cx).project_path(cx)?;
 9967            let project = self.project.as_ref()?.read(cx);
 9968            let entry = project.entry_for_path(&project_path, cx)?;
 9969            let parent = match &entry.canonical_path {
 9970                Some(canonical_path) => canonical_path.to_path_buf(),
 9971                None => project.absolute_path(&project_path, cx)?,
 9972            }
 9973            .parent()?
 9974            .to_path_buf();
 9975            Some(parent)
 9976        }) {
 9977            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9978        }
 9979    }
 9980
 9981    fn set_breakpoint_context_menu(
 9982        &mut self,
 9983        display_row: DisplayRow,
 9984        position: Option<Anchor>,
 9985        clicked_point: gpui::Point<Pixels>,
 9986        window: &mut Window,
 9987        cx: &mut Context<Self>,
 9988    ) {
 9989        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9990            return;
 9991        }
 9992        let source = self
 9993            .buffer
 9994            .read(cx)
 9995            .snapshot(cx)
 9996            .anchor_before(Point::new(display_row.0, 0u32));
 9997
 9998        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9999
10000        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10001            self,
10002            source,
10003            clicked_point,
10004            context_menu,
10005            window,
10006            cx,
10007        );
10008    }
10009
10010    fn add_edit_breakpoint_block(
10011        &mut self,
10012        anchor: Anchor,
10013        breakpoint: &Breakpoint,
10014        edit_action: BreakpointPromptEditAction,
10015        window: &mut Window,
10016        cx: &mut Context<Self>,
10017    ) {
10018        let weak_editor = cx.weak_entity();
10019        let bp_prompt = cx.new(|cx| {
10020            BreakpointPromptEditor::new(
10021                weak_editor,
10022                anchor,
10023                breakpoint.clone(),
10024                edit_action,
10025                window,
10026                cx,
10027            )
10028        });
10029
10030        let height = bp_prompt.update(cx, |this, cx| {
10031            this.prompt
10032                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10033        });
10034        let cloned_prompt = bp_prompt.clone();
10035        let blocks = vec![BlockProperties {
10036            style: BlockStyle::Sticky,
10037            placement: BlockPlacement::Above(anchor),
10038            height: Some(height),
10039            render: Arc::new(move |cx| {
10040                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10041                cloned_prompt.clone().into_any_element()
10042            }),
10043            priority: 0,
10044            render_in_minimap: true,
10045        }];
10046
10047        let focus_handle = bp_prompt.focus_handle(cx);
10048        window.focus(&focus_handle);
10049
10050        let block_ids = self.insert_blocks(blocks, None, cx);
10051        bp_prompt.update(cx, |prompt, _| {
10052            prompt.add_block_ids(block_ids);
10053        });
10054    }
10055
10056    pub(crate) fn breakpoint_at_row(
10057        &self,
10058        row: u32,
10059        window: &mut Window,
10060        cx: &mut Context<Self>,
10061    ) -> Option<(Anchor, Breakpoint)> {
10062        let snapshot = self.snapshot(window, cx);
10063        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10064
10065        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10066    }
10067
10068    pub(crate) fn breakpoint_at_anchor(
10069        &self,
10070        breakpoint_position: Anchor,
10071        snapshot: &EditorSnapshot,
10072        cx: &mut Context<Self>,
10073    ) -> Option<(Anchor, Breakpoint)> {
10074        let project = self.project.clone()?;
10075
10076        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10077            snapshot
10078                .buffer_snapshot
10079                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10080        })?;
10081
10082        let enclosing_excerpt = breakpoint_position.excerpt_id;
10083        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10084        let buffer_snapshot = buffer.read(cx).snapshot();
10085
10086        let row = buffer_snapshot
10087            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10088            .row;
10089
10090        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10091        let anchor_end = snapshot
10092            .buffer_snapshot
10093            .anchor_after(Point::new(row, line_len));
10094
10095        let bp = self
10096            .breakpoint_store
10097            .as_ref()?
10098            .read_with(cx, |breakpoint_store, cx| {
10099                breakpoint_store
10100                    .breakpoints(
10101                        &buffer,
10102                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10103                        &buffer_snapshot,
10104                        cx,
10105                    )
10106                    .next()
10107                    .and_then(|(bp, _)| {
10108                        let breakpoint_row = buffer_snapshot
10109                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10110                            .row;
10111
10112                        if breakpoint_row == row {
10113                            snapshot
10114                                .buffer_snapshot
10115                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10116                                .map(|position| (position, bp.bp.clone()))
10117                        } else {
10118                            None
10119                        }
10120                    })
10121            });
10122        bp
10123    }
10124
10125    pub fn edit_log_breakpoint(
10126        &mut self,
10127        _: &EditLogBreakpoint,
10128        window: &mut Window,
10129        cx: &mut Context<Self>,
10130    ) {
10131        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10132            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10133                message: None,
10134                state: BreakpointState::Enabled,
10135                condition: None,
10136                hit_condition: None,
10137            });
10138
10139            self.add_edit_breakpoint_block(
10140                anchor,
10141                &breakpoint,
10142                BreakpointPromptEditAction::Log,
10143                window,
10144                cx,
10145            );
10146        }
10147    }
10148
10149    fn breakpoints_at_cursors(
10150        &self,
10151        window: &mut Window,
10152        cx: &mut Context<Self>,
10153    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10154        let snapshot = self.snapshot(window, cx);
10155        let cursors = self
10156            .selections
10157            .disjoint_anchors()
10158            .into_iter()
10159            .map(|selection| {
10160                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10161
10162                let breakpoint_position = self
10163                    .breakpoint_at_row(cursor_position.row, window, cx)
10164                    .map(|bp| bp.0)
10165                    .unwrap_or_else(|| {
10166                        snapshot
10167                            .display_snapshot
10168                            .buffer_snapshot
10169                            .anchor_after(Point::new(cursor_position.row, 0))
10170                    });
10171
10172                let breakpoint = self
10173                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10174                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10175
10176                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10177            })
10178            // 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.
10179            .collect::<HashMap<Anchor, _>>();
10180
10181        cursors.into_iter().collect()
10182    }
10183
10184    pub fn enable_breakpoint(
10185        &mut self,
10186        _: &crate::actions::EnableBreakpoint,
10187        window: &mut Window,
10188        cx: &mut Context<Self>,
10189    ) {
10190        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10191            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10192                continue;
10193            };
10194            self.edit_breakpoint_at_anchor(
10195                anchor,
10196                breakpoint,
10197                BreakpointEditAction::InvertState,
10198                cx,
10199            );
10200        }
10201    }
10202
10203    pub fn disable_breakpoint(
10204        &mut self,
10205        _: &crate::actions::DisableBreakpoint,
10206        window: &mut Window,
10207        cx: &mut Context<Self>,
10208    ) {
10209        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10210            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10211                continue;
10212            };
10213            self.edit_breakpoint_at_anchor(
10214                anchor,
10215                breakpoint,
10216                BreakpointEditAction::InvertState,
10217                cx,
10218            );
10219        }
10220    }
10221
10222    pub fn toggle_breakpoint(
10223        &mut self,
10224        _: &crate::actions::ToggleBreakpoint,
10225        window: &mut Window,
10226        cx: &mut Context<Self>,
10227    ) {
10228        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10229            if let Some(breakpoint) = breakpoint {
10230                self.edit_breakpoint_at_anchor(
10231                    anchor,
10232                    breakpoint,
10233                    BreakpointEditAction::Toggle,
10234                    cx,
10235                );
10236            } else {
10237                self.edit_breakpoint_at_anchor(
10238                    anchor,
10239                    Breakpoint::new_standard(),
10240                    BreakpointEditAction::Toggle,
10241                    cx,
10242                );
10243            }
10244        }
10245    }
10246
10247    pub fn edit_breakpoint_at_anchor(
10248        &mut self,
10249        breakpoint_position: Anchor,
10250        breakpoint: Breakpoint,
10251        edit_action: BreakpointEditAction,
10252        cx: &mut Context<Self>,
10253    ) {
10254        let Some(breakpoint_store) = &self.breakpoint_store else {
10255            return;
10256        };
10257
10258        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10259            if breakpoint_position == Anchor::min() {
10260                self.buffer()
10261                    .read(cx)
10262                    .excerpt_buffer_ids()
10263                    .into_iter()
10264                    .next()
10265            } else {
10266                None
10267            }
10268        }) else {
10269            return;
10270        };
10271
10272        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10273            return;
10274        };
10275
10276        breakpoint_store.update(cx, |breakpoint_store, cx| {
10277            breakpoint_store.toggle_breakpoint(
10278                buffer,
10279                BreakpointWithPosition {
10280                    position: breakpoint_position.text_anchor,
10281                    bp: breakpoint,
10282                },
10283                edit_action,
10284                cx,
10285            );
10286        });
10287
10288        cx.notify();
10289    }
10290
10291    #[cfg(any(test, feature = "test-support"))]
10292    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10293        self.breakpoint_store.clone()
10294    }
10295
10296    pub fn prepare_restore_change(
10297        &self,
10298        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10299        hunk: &MultiBufferDiffHunk,
10300        cx: &mut App,
10301    ) -> Option<()> {
10302        if hunk.is_created_file() {
10303            return None;
10304        }
10305        let buffer = self.buffer.read(cx);
10306        let diff = buffer.diff_for(hunk.buffer_id)?;
10307        let buffer = buffer.buffer(hunk.buffer_id)?;
10308        let buffer = buffer.read(cx);
10309        let original_text = diff
10310            .read(cx)
10311            .base_text()
10312            .as_rope()
10313            .slice(hunk.diff_base_byte_range.clone());
10314        let buffer_snapshot = buffer.snapshot();
10315        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10316        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10317            probe
10318                .0
10319                .start
10320                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10321                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10322        }) {
10323            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10324            Some(())
10325        } else {
10326            None
10327        }
10328    }
10329
10330    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10331        self.manipulate_lines(window, cx, |lines| lines.reverse())
10332    }
10333
10334    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10335        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10336    }
10337
10338    fn manipulate_lines<Fn>(
10339        &mut self,
10340        window: &mut Window,
10341        cx: &mut Context<Self>,
10342        mut callback: Fn,
10343    ) where
10344        Fn: FnMut(&mut Vec<&str>),
10345    {
10346        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10347
10348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10349        let buffer = self.buffer.read(cx).snapshot(cx);
10350
10351        let mut edits = Vec::new();
10352
10353        let selections = self.selections.all::<Point>(cx);
10354        let mut selections = selections.iter().peekable();
10355        let mut contiguous_row_selections = Vec::new();
10356        let mut new_selections = Vec::new();
10357        let mut added_lines = 0;
10358        let mut removed_lines = 0;
10359
10360        while let Some(selection) = selections.next() {
10361            let (start_row, end_row) = consume_contiguous_rows(
10362                &mut contiguous_row_selections,
10363                selection,
10364                &display_map,
10365                &mut selections,
10366            );
10367
10368            let start_point = Point::new(start_row.0, 0);
10369            let end_point = Point::new(
10370                end_row.previous_row().0,
10371                buffer.line_len(end_row.previous_row()),
10372            );
10373            let text = buffer
10374                .text_for_range(start_point..end_point)
10375                .collect::<String>();
10376
10377            let mut lines = text.split('\n').collect_vec();
10378
10379            let lines_before = lines.len();
10380            callback(&mut lines);
10381            let lines_after = lines.len();
10382
10383            edits.push((start_point..end_point, lines.join("\n")));
10384
10385            // Selections must change based on added and removed line count
10386            let start_row =
10387                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10388            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10389            new_selections.push(Selection {
10390                id: selection.id,
10391                start: start_row,
10392                end: end_row,
10393                goal: SelectionGoal::None,
10394                reversed: selection.reversed,
10395            });
10396
10397            if lines_after > lines_before {
10398                added_lines += lines_after - lines_before;
10399            } else if lines_before > lines_after {
10400                removed_lines += lines_before - lines_after;
10401            }
10402        }
10403
10404        self.transact(window, cx, |this, window, cx| {
10405            let buffer = this.buffer.update(cx, |buffer, cx| {
10406                buffer.edit(edits, None, cx);
10407                buffer.snapshot(cx)
10408            });
10409
10410            // Recalculate offsets on newly edited buffer
10411            let new_selections = new_selections
10412                .iter()
10413                .map(|s| {
10414                    let start_point = Point::new(s.start.0, 0);
10415                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10416                    Selection {
10417                        id: s.id,
10418                        start: buffer.point_to_offset(start_point),
10419                        end: buffer.point_to_offset(end_point),
10420                        goal: s.goal,
10421                        reversed: s.reversed,
10422                    }
10423                })
10424                .collect();
10425
10426            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10427                s.select(new_selections);
10428            });
10429
10430            this.request_autoscroll(Autoscroll::fit(), cx);
10431        });
10432    }
10433
10434    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10435        self.manipulate_text(window, cx, |text| {
10436            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10437            if has_upper_case_characters {
10438                text.to_lowercase()
10439            } else {
10440                text.to_uppercase()
10441            }
10442        })
10443    }
10444
10445    pub fn convert_to_upper_case(
10446        &mut self,
10447        _: &ConvertToUpperCase,
10448        window: &mut Window,
10449        cx: &mut Context<Self>,
10450    ) {
10451        self.manipulate_text(window, cx, |text| text.to_uppercase())
10452    }
10453
10454    pub fn convert_to_lower_case(
10455        &mut self,
10456        _: &ConvertToLowerCase,
10457        window: &mut Window,
10458        cx: &mut Context<Self>,
10459    ) {
10460        self.manipulate_text(window, cx, |text| text.to_lowercase())
10461    }
10462
10463    pub fn convert_to_title_case(
10464        &mut self,
10465        _: &ConvertToTitleCase,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        self.manipulate_text(window, cx, |text| {
10470            text.split('\n')
10471                .map(|line| line.to_case(Case::Title))
10472                .join("\n")
10473        })
10474    }
10475
10476    pub fn convert_to_snake_case(
10477        &mut self,
10478        _: &ConvertToSnakeCase,
10479        window: &mut Window,
10480        cx: &mut Context<Self>,
10481    ) {
10482        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10483    }
10484
10485    pub fn convert_to_kebab_case(
10486        &mut self,
10487        _: &ConvertToKebabCase,
10488        window: &mut Window,
10489        cx: &mut Context<Self>,
10490    ) {
10491        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10492    }
10493
10494    pub fn convert_to_upper_camel_case(
10495        &mut self,
10496        _: &ConvertToUpperCamelCase,
10497        window: &mut Window,
10498        cx: &mut Context<Self>,
10499    ) {
10500        self.manipulate_text(window, cx, |text| {
10501            text.split('\n')
10502                .map(|line| line.to_case(Case::UpperCamel))
10503                .join("\n")
10504        })
10505    }
10506
10507    pub fn convert_to_lower_camel_case(
10508        &mut self,
10509        _: &ConvertToLowerCamelCase,
10510        window: &mut Window,
10511        cx: &mut Context<Self>,
10512    ) {
10513        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10514    }
10515
10516    pub fn convert_to_opposite_case(
10517        &mut self,
10518        _: &ConvertToOppositeCase,
10519        window: &mut Window,
10520        cx: &mut Context<Self>,
10521    ) {
10522        self.manipulate_text(window, cx, |text| {
10523            text.chars()
10524                .fold(String::with_capacity(text.len()), |mut t, c| {
10525                    if c.is_uppercase() {
10526                        t.extend(c.to_lowercase());
10527                    } else {
10528                        t.extend(c.to_uppercase());
10529                    }
10530                    t
10531                })
10532        })
10533    }
10534
10535    pub fn convert_to_rot13(
10536        &mut self,
10537        _: &ConvertToRot13,
10538        window: &mut Window,
10539        cx: &mut Context<Self>,
10540    ) {
10541        self.manipulate_text(window, cx, |text| {
10542            text.chars()
10543                .map(|c| match c {
10544                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10545                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10546                    _ => c,
10547                })
10548                .collect()
10549        })
10550    }
10551
10552    pub fn convert_to_rot47(
10553        &mut self,
10554        _: &ConvertToRot47,
10555        window: &mut Window,
10556        cx: &mut Context<Self>,
10557    ) {
10558        self.manipulate_text(window, cx, |text| {
10559            text.chars()
10560                .map(|c| {
10561                    let code_point = c as u32;
10562                    if code_point >= 33 && code_point <= 126 {
10563                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10564                    }
10565                    c
10566                })
10567                .collect()
10568        })
10569    }
10570
10571    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10572    where
10573        Fn: FnMut(&str) -> String,
10574    {
10575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10576        let buffer = self.buffer.read(cx).snapshot(cx);
10577
10578        let mut new_selections = Vec::new();
10579        let mut edits = Vec::new();
10580        let mut selection_adjustment = 0i32;
10581
10582        for selection in self.selections.all::<usize>(cx) {
10583            let selection_is_empty = selection.is_empty();
10584
10585            let (start, end) = if selection_is_empty {
10586                let word_range = movement::surrounding_word(
10587                    &display_map,
10588                    selection.start.to_display_point(&display_map),
10589                );
10590                let start = word_range.start.to_offset(&display_map, Bias::Left);
10591                let end = word_range.end.to_offset(&display_map, Bias::Left);
10592                (start, end)
10593            } else {
10594                (selection.start, selection.end)
10595            };
10596
10597            let text = buffer.text_for_range(start..end).collect::<String>();
10598            let old_length = text.len() as i32;
10599            let text = callback(&text);
10600
10601            new_selections.push(Selection {
10602                start: (start as i32 - selection_adjustment) as usize,
10603                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10604                goal: SelectionGoal::None,
10605                ..selection
10606            });
10607
10608            selection_adjustment += old_length - text.len() as i32;
10609
10610            edits.push((start..end, text));
10611        }
10612
10613        self.transact(window, cx, |this, window, cx| {
10614            this.buffer.update(cx, |buffer, cx| {
10615                buffer.edit(edits, None, cx);
10616            });
10617
10618            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10619                s.select(new_selections);
10620            });
10621
10622            this.request_autoscroll(Autoscroll::fit(), cx);
10623        });
10624    }
10625
10626    pub fn move_selection_on_drop(
10627        &mut self,
10628        selection: &Selection<Anchor>,
10629        target: DisplayPoint,
10630        is_cut: bool,
10631        window: &mut Window,
10632        cx: &mut Context<Self>,
10633    ) {
10634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10635        let buffer = &display_map.buffer_snapshot;
10636        let mut edits = Vec::new();
10637        let insert_point = display_map
10638            .clip_point(target, Bias::Left)
10639            .to_point(&display_map);
10640        let text = buffer
10641            .text_for_range(selection.start..selection.end)
10642            .collect::<String>();
10643        if is_cut {
10644            edits.push(((selection.start..selection.end), String::new()));
10645        }
10646        let insert_anchor = buffer.anchor_before(insert_point);
10647        edits.push(((insert_anchor..insert_anchor), text));
10648        let last_edit_start = insert_anchor.bias_left(buffer);
10649        let last_edit_end = insert_anchor.bias_right(buffer);
10650        self.transact(window, cx, |this, window, cx| {
10651            this.buffer.update(cx, |buffer, cx| {
10652                buffer.edit(edits, None, cx);
10653            });
10654            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10655                s.select_anchor_ranges([last_edit_start..last_edit_end]);
10656            });
10657        });
10658    }
10659
10660    pub fn clear_selection_drag_state(&mut self) {
10661        self.selection_drag_state = SelectionDragState::None;
10662    }
10663
10664    pub fn duplicate(
10665        &mut self,
10666        upwards: bool,
10667        whole_lines: bool,
10668        window: &mut Window,
10669        cx: &mut Context<Self>,
10670    ) {
10671        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10672
10673        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10674        let buffer = &display_map.buffer_snapshot;
10675        let selections = self.selections.all::<Point>(cx);
10676
10677        let mut edits = Vec::new();
10678        let mut selections_iter = selections.iter().peekable();
10679        while let Some(selection) = selections_iter.next() {
10680            let mut rows = selection.spanned_rows(false, &display_map);
10681            // duplicate line-wise
10682            if whole_lines || selection.start == selection.end {
10683                // Avoid duplicating the same lines twice.
10684                while let Some(next_selection) = selections_iter.peek() {
10685                    let next_rows = next_selection.spanned_rows(false, &display_map);
10686                    if next_rows.start < rows.end {
10687                        rows.end = next_rows.end;
10688                        selections_iter.next().unwrap();
10689                    } else {
10690                        break;
10691                    }
10692                }
10693
10694                // Copy the text from the selected row region and splice it either at the start
10695                // or end of the region.
10696                let start = Point::new(rows.start.0, 0);
10697                let end = Point::new(
10698                    rows.end.previous_row().0,
10699                    buffer.line_len(rows.end.previous_row()),
10700                );
10701                let text = buffer
10702                    .text_for_range(start..end)
10703                    .chain(Some("\n"))
10704                    .collect::<String>();
10705                let insert_location = if upwards {
10706                    Point::new(rows.end.0, 0)
10707                } else {
10708                    start
10709                };
10710                edits.push((insert_location..insert_location, text));
10711            } else {
10712                // duplicate character-wise
10713                let start = selection.start;
10714                let end = selection.end;
10715                let text = buffer.text_for_range(start..end).collect::<String>();
10716                edits.push((selection.end..selection.end, text));
10717            }
10718        }
10719
10720        self.transact(window, cx, |this, _, cx| {
10721            this.buffer.update(cx, |buffer, cx| {
10722                buffer.edit(edits, None, cx);
10723            });
10724
10725            this.request_autoscroll(Autoscroll::fit(), cx);
10726        });
10727    }
10728
10729    pub fn duplicate_line_up(
10730        &mut self,
10731        _: &DuplicateLineUp,
10732        window: &mut Window,
10733        cx: &mut Context<Self>,
10734    ) {
10735        self.duplicate(true, true, window, cx);
10736    }
10737
10738    pub fn duplicate_line_down(
10739        &mut self,
10740        _: &DuplicateLineDown,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743    ) {
10744        self.duplicate(false, true, window, cx);
10745    }
10746
10747    pub fn duplicate_selection(
10748        &mut self,
10749        _: &DuplicateSelection,
10750        window: &mut Window,
10751        cx: &mut Context<Self>,
10752    ) {
10753        self.duplicate(false, false, window, cx);
10754    }
10755
10756    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10757        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10758
10759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10760        let buffer = self.buffer.read(cx).snapshot(cx);
10761
10762        let mut edits = Vec::new();
10763        let mut unfold_ranges = Vec::new();
10764        let mut refold_creases = Vec::new();
10765
10766        let selections = self.selections.all::<Point>(cx);
10767        let mut selections = selections.iter().peekable();
10768        let mut contiguous_row_selections = Vec::new();
10769        let mut new_selections = Vec::new();
10770
10771        while let Some(selection) = selections.next() {
10772            // Find all the selections that span a contiguous row range
10773            let (start_row, end_row) = consume_contiguous_rows(
10774                &mut contiguous_row_selections,
10775                selection,
10776                &display_map,
10777                &mut selections,
10778            );
10779
10780            // Move the text spanned by the row range to be before the line preceding the row range
10781            if start_row.0 > 0 {
10782                let range_to_move = Point::new(
10783                    start_row.previous_row().0,
10784                    buffer.line_len(start_row.previous_row()),
10785                )
10786                    ..Point::new(
10787                        end_row.previous_row().0,
10788                        buffer.line_len(end_row.previous_row()),
10789                    );
10790                let insertion_point = display_map
10791                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10792                    .0;
10793
10794                // Don't move lines across excerpts
10795                if buffer
10796                    .excerpt_containing(insertion_point..range_to_move.end)
10797                    .is_some()
10798                {
10799                    let text = buffer
10800                        .text_for_range(range_to_move.clone())
10801                        .flat_map(|s| s.chars())
10802                        .skip(1)
10803                        .chain(['\n'])
10804                        .collect::<String>();
10805
10806                    edits.push((
10807                        buffer.anchor_after(range_to_move.start)
10808                            ..buffer.anchor_before(range_to_move.end),
10809                        String::new(),
10810                    ));
10811                    let insertion_anchor = buffer.anchor_after(insertion_point);
10812                    edits.push((insertion_anchor..insertion_anchor, text));
10813
10814                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10815
10816                    // Move selections up
10817                    new_selections.extend(contiguous_row_selections.drain(..).map(
10818                        |mut selection| {
10819                            selection.start.row -= row_delta;
10820                            selection.end.row -= row_delta;
10821                            selection
10822                        },
10823                    ));
10824
10825                    // Move folds up
10826                    unfold_ranges.push(range_to_move.clone());
10827                    for fold in display_map.folds_in_range(
10828                        buffer.anchor_before(range_to_move.start)
10829                            ..buffer.anchor_after(range_to_move.end),
10830                    ) {
10831                        let mut start = fold.range.start.to_point(&buffer);
10832                        let mut end = fold.range.end.to_point(&buffer);
10833                        start.row -= row_delta;
10834                        end.row -= row_delta;
10835                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10836                    }
10837                }
10838            }
10839
10840            // If we didn't move line(s), preserve the existing selections
10841            new_selections.append(&mut contiguous_row_selections);
10842        }
10843
10844        self.transact(window, cx, |this, window, cx| {
10845            this.unfold_ranges(&unfold_ranges, true, true, cx);
10846            this.buffer.update(cx, |buffer, cx| {
10847                for (range, text) in edits {
10848                    buffer.edit([(range, text)], None, cx);
10849                }
10850            });
10851            this.fold_creases(refold_creases, true, window, cx);
10852            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10853                s.select(new_selections);
10854            })
10855        });
10856    }
10857
10858    pub fn move_line_down(
10859        &mut self,
10860        _: &MoveLineDown,
10861        window: &mut Window,
10862        cx: &mut Context<Self>,
10863    ) {
10864        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10865
10866        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10867        let buffer = self.buffer.read(cx).snapshot(cx);
10868
10869        let mut edits = Vec::new();
10870        let mut unfold_ranges = Vec::new();
10871        let mut refold_creases = Vec::new();
10872
10873        let selections = self.selections.all::<Point>(cx);
10874        let mut selections = selections.iter().peekable();
10875        let mut contiguous_row_selections = Vec::new();
10876        let mut new_selections = Vec::new();
10877
10878        while let Some(selection) = selections.next() {
10879            // Find all the selections that span a contiguous row range
10880            let (start_row, end_row) = consume_contiguous_rows(
10881                &mut contiguous_row_selections,
10882                selection,
10883                &display_map,
10884                &mut selections,
10885            );
10886
10887            // Move the text spanned by the row range to be after the last line of the row range
10888            if end_row.0 <= buffer.max_point().row {
10889                let range_to_move =
10890                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10891                let insertion_point = display_map
10892                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10893                    .0;
10894
10895                // Don't move lines across excerpt boundaries
10896                if buffer
10897                    .excerpt_containing(range_to_move.start..insertion_point)
10898                    .is_some()
10899                {
10900                    let mut text = String::from("\n");
10901                    text.extend(buffer.text_for_range(range_to_move.clone()));
10902                    text.pop(); // Drop trailing newline
10903                    edits.push((
10904                        buffer.anchor_after(range_to_move.start)
10905                            ..buffer.anchor_before(range_to_move.end),
10906                        String::new(),
10907                    ));
10908                    let insertion_anchor = buffer.anchor_after(insertion_point);
10909                    edits.push((insertion_anchor..insertion_anchor, text));
10910
10911                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10912
10913                    // Move selections down
10914                    new_selections.extend(contiguous_row_selections.drain(..).map(
10915                        |mut selection| {
10916                            selection.start.row += row_delta;
10917                            selection.end.row += row_delta;
10918                            selection
10919                        },
10920                    ));
10921
10922                    // Move folds down
10923                    unfold_ranges.push(range_to_move.clone());
10924                    for fold in display_map.folds_in_range(
10925                        buffer.anchor_before(range_to_move.start)
10926                            ..buffer.anchor_after(range_to_move.end),
10927                    ) {
10928                        let mut start = fold.range.start.to_point(&buffer);
10929                        let mut end = fold.range.end.to_point(&buffer);
10930                        start.row += row_delta;
10931                        end.row += row_delta;
10932                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10933                    }
10934                }
10935            }
10936
10937            // If we didn't move line(s), preserve the existing selections
10938            new_selections.append(&mut contiguous_row_selections);
10939        }
10940
10941        self.transact(window, cx, |this, window, cx| {
10942            this.unfold_ranges(&unfold_ranges, true, true, cx);
10943            this.buffer.update(cx, |buffer, cx| {
10944                for (range, text) in edits {
10945                    buffer.edit([(range, text)], None, cx);
10946                }
10947            });
10948            this.fold_creases(refold_creases, true, window, cx);
10949            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10950                s.select(new_selections)
10951            });
10952        });
10953    }
10954
10955    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10956        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10957        let text_layout_details = &self.text_layout_details(window);
10958        self.transact(window, cx, |this, window, cx| {
10959            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10960                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10961                s.move_with(|display_map, selection| {
10962                    if !selection.is_empty() {
10963                        return;
10964                    }
10965
10966                    let mut head = selection.head();
10967                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10968                    if head.column() == display_map.line_len(head.row()) {
10969                        transpose_offset = display_map
10970                            .buffer_snapshot
10971                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10972                    }
10973
10974                    if transpose_offset == 0 {
10975                        return;
10976                    }
10977
10978                    *head.column_mut() += 1;
10979                    head = display_map.clip_point(head, Bias::Right);
10980                    let goal = SelectionGoal::HorizontalPosition(
10981                        display_map
10982                            .x_for_display_point(head, text_layout_details)
10983                            .into(),
10984                    );
10985                    selection.collapse_to(head, goal);
10986
10987                    let transpose_start = display_map
10988                        .buffer_snapshot
10989                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10990                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10991                        let transpose_end = display_map
10992                            .buffer_snapshot
10993                            .clip_offset(transpose_offset + 1, Bias::Right);
10994                        if let Some(ch) =
10995                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10996                        {
10997                            edits.push((transpose_start..transpose_offset, String::new()));
10998                            edits.push((transpose_end..transpose_end, ch.to_string()));
10999                        }
11000                    }
11001                });
11002                edits
11003            });
11004            this.buffer
11005                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11006            let selections = this.selections.all::<usize>(cx);
11007            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11008                s.select(selections);
11009            });
11010        });
11011    }
11012
11013    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11014        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11015        self.rewrap_impl(RewrapOptions::default(), cx)
11016    }
11017
11018    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11019        let buffer = self.buffer.read(cx).snapshot(cx);
11020        let selections = self.selections.all::<Point>(cx);
11021
11022        // Shrink and split selections to respect paragraph boundaries.
11023        let ranges = selections.into_iter().flat_map(|selection| {
11024            let language_settings = buffer.language_settings_at(selection.head(), cx);
11025            let language_scope = buffer.language_scope_at(selection.head());
11026
11027            let Some(start_row) = (selection.start.row..=selection.end.row)
11028                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11029            else {
11030                return vec![];
11031            };
11032            let Some(end_row) = (selection.start.row..=selection.end.row)
11033                .rev()
11034                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11035            else {
11036                return vec![];
11037            };
11038
11039            let mut row = start_row;
11040            let mut ranges = Vec::new();
11041            while let Some(blank_row) =
11042                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11043            {
11044                let next_paragraph_start = (blank_row + 1..=end_row)
11045                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11046                    .unwrap();
11047                ranges.push((
11048                    language_settings.clone(),
11049                    language_scope.clone(),
11050                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11051                ));
11052                row = next_paragraph_start;
11053            }
11054            ranges.push((
11055                language_settings.clone(),
11056                language_scope.clone(),
11057                Point::new(row, 0)..Point::new(end_row, 0),
11058            ));
11059
11060            ranges
11061        });
11062
11063        let mut edits = Vec::new();
11064        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11065
11066        for (language_settings, language_scope, range) in ranges {
11067            let mut start_row = range.start.row;
11068            let mut end_row = range.end.row;
11069
11070            // Skip selections that overlap with a range that has already been rewrapped.
11071            let selection_range = start_row..end_row;
11072            if rewrapped_row_ranges
11073                .iter()
11074                .any(|range| range.overlaps(&selection_range))
11075            {
11076                continue;
11077            }
11078
11079            let tab_size = language_settings.tab_size;
11080
11081            // Since not all lines in the selection may be at the same indent
11082            // level, choose the indent size that is the most common between all
11083            // of the lines.
11084            //
11085            // If there is a tie, we use the deepest indent.
11086            let (indent_size, indent_end) = {
11087                let mut indent_size_occurrences = HashMap::default();
11088                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11089
11090                for row in start_row..=end_row {
11091                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11092                    rows_by_indent_size.entry(indent).or_default().push(row);
11093                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11094                }
11095
11096                let indent_size = indent_size_occurrences
11097                    .into_iter()
11098                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11099                    .map(|(indent, _)| indent)
11100                    .unwrap_or_default();
11101                let row = rows_by_indent_size[&indent_size][0];
11102                let indent_end = Point::new(row, indent_size.len);
11103
11104                (indent_size, indent_end)
11105            };
11106
11107            let mut line_prefix = indent_size.chars().collect::<String>();
11108
11109            let mut inside_comment = false;
11110            if let Some(comment_prefix) = language_scope.and_then(|language| {
11111                language
11112                    .line_comment_prefixes()
11113                    .iter()
11114                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11115                    .cloned()
11116            }) {
11117                line_prefix.push_str(&comment_prefix);
11118                inside_comment = true;
11119            }
11120
11121            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11122                RewrapBehavior::InComments => inside_comment,
11123                RewrapBehavior::InSelections => !range.is_empty(),
11124                RewrapBehavior::Anywhere => true,
11125            };
11126
11127            let should_rewrap = options.override_language_settings
11128                || allow_rewrap_based_on_language
11129                || self.hard_wrap.is_some();
11130            if !should_rewrap {
11131                continue;
11132            }
11133
11134            if range.is_empty() {
11135                'expand_upwards: while start_row > 0 {
11136                    let prev_row = start_row - 1;
11137                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11138                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11139                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11140                    {
11141                        start_row = prev_row;
11142                    } else {
11143                        break 'expand_upwards;
11144                    }
11145                }
11146
11147                'expand_downwards: while end_row < buffer.max_point().row {
11148                    let next_row = end_row + 1;
11149                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11150                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11151                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11152                    {
11153                        end_row = next_row;
11154                    } else {
11155                        break 'expand_downwards;
11156                    }
11157                }
11158            }
11159
11160            let start = Point::new(start_row, 0);
11161            let start_offset = start.to_offset(&buffer);
11162            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11163            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11164            let Some(lines_without_prefixes) = selection_text
11165                .lines()
11166                .map(|line| {
11167                    line.strip_prefix(&line_prefix)
11168                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11169                        .with_context(|| {
11170                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11171                        })
11172                })
11173                .collect::<Result<Vec<_>, _>>()
11174                .log_err()
11175            else {
11176                continue;
11177            };
11178
11179            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11180                buffer
11181                    .language_settings_at(Point::new(start_row, 0), cx)
11182                    .preferred_line_length as usize
11183            });
11184            let wrapped_text = wrap_with_prefix(
11185                line_prefix,
11186                lines_without_prefixes.join("\n"),
11187                wrap_column,
11188                tab_size,
11189                options.preserve_existing_whitespace,
11190            );
11191
11192            // TODO: should always use char-based diff while still supporting cursor behavior that
11193            // matches vim.
11194            let mut diff_options = DiffOptions::default();
11195            if options.override_language_settings {
11196                diff_options.max_word_diff_len = 0;
11197                diff_options.max_word_diff_line_count = 0;
11198            } else {
11199                diff_options.max_word_diff_len = usize::MAX;
11200                diff_options.max_word_diff_line_count = usize::MAX;
11201            }
11202
11203            for (old_range, new_text) in
11204                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11205            {
11206                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11207                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11208                edits.push((edit_start..edit_end, new_text));
11209            }
11210
11211            rewrapped_row_ranges.push(start_row..=end_row);
11212        }
11213
11214        self.buffer
11215            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11216    }
11217
11218    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11219        let mut text = String::new();
11220        let buffer = self.buffer.read(cx).snapshot(cx);
11221        let mut selections = self.selections.all::<Point>(cx);
11222        let mut clipboard_selections = Vec::with_capacity(selections.len());
11223        {
11224            let max_point = buffer.max_point();
11225            let mut is_first = true;
11226            for selection in &mut selections {
11227                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11228                if is_entire_line {
11229                    selection.start = Point::new(selection.start.row, 0);
11230                    if !selection.is_empty() && selection.end.column == 0 {
11231                        selection.end = cmp::min(max_point, selection.end);
11232                    } else {
11233                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11234                    }
11235                    selection.goal = SelectionGoal::None;
11236                }
11237                if is_first {
11238                    is_first = false;
11239                } else {
11240                    text += "\n";
11241                }
11242                let mut len = 0;
11243                for chunk in buffer.text_for_range(selection.start..selection.end) {
11244                    text.push_str(chunk);
11245                    len += chunk.len();
11246                }
11247                clipboard_selections.push(ClipboardSelection {
11248                    len,
11249                    is_entire_line,
11250                    first_line_indent: buffer
11251                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11252                        .len,
11253                });
11254            }
11255        }
11256
11257        self.transact(window, cx, |this, window, cx| {
11258            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11259                s.select(selections);
11260            });
11261            this.insert("", window, cx);
11262        });
11263        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11264    }
11265
11266    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11267        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11268        let item = self.cut_common(window, cx);
11269        cx.write_to_clipboard(item);
11270    }
11271
11272    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11273        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11274        self.change_selections(None, window, cx, |s| {
11275            s.move_with(|snapshot, sel| {
11276                if sel.is_empty() {
11277                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11278                }
11279            });
11280        });
11281        let item = self.cut_common(window, cx);
11282        cx.set_global(KillRing(item))
11283    }
11284
11285    pub fn kill_ring_yank(
11286        &mut self,
11287        _: &KillRingYank,
11288        window: &mut Window,
11289        cx: &mut Context<Self>,
11290    ) {
11291        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11292        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11293            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11294                (kill_ring.text().to_string(), kill_ring.metadata_json())
11295            } else {
11296                return;
11297            }
11298        } else {
11299            return;
11300        };
11301        self.do_paste(&text, metadata, false, window, cx);
11302    }
11303
11304    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11305        self.do_copy(true, cx);
11306    }
11307
11308    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11309        self.do_copy(false, cx);
11310    }
11311
11312    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11313        let selections = self.selections.all::<Point>(cx);
11314        let buffer = self.buffer.read(cx).read(cx);
11315        let mut text = String::new();
11316
11317        let mut clipboard_selections = Vec::with_capacity(selections.len());
11318        {
11319            let max_point = buffer.max_point();
11320            let mut is_first = true;
11321            for selection in &selections {
11322                let mut start = selection.start;
11323                let mut end = selection.end;
11324                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11325                if is_entire_line {
11326                    start = Point::new(start.row, 0);
11327                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11328                }
11329
11330                let mut trimmed_selections = Vec::new();
11331                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11332                    let row = MultiBufferRow(start.row);
11333                    let first_indent = buffer.indent_size_for_line(row);
11334                    if first_indent.len == 0 || start.column > first_indent.len {
11335                        trimmed_selections.push(start..end);
11336                    } else {
11337                        trimmed_selections.push(
11338                            Point::new(row.0, first_indent.len)
11339                                ..Point::new(row.0, buffer.line_len(row)),
11340                        );
11341                        for row in start.row + 1..=end.row {
11342                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11343                            if row == end.row {
11344                                line_len = end.column;
11345                            }
11346                            if line_len == 0 {
11347                                trimmed_selections
11348                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11349                                continue;
11350                            }
11351                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11352                            if row_indent_size.len >= first_indent.len {
11353                                trimmed_selections.push(
11354                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11355                                );
11356                            } else {
11357                                trimmed_selections.clear();
11358                                trimmed_selections.push(start..end);
11359                                break;
11360                            }
11361                        }
11362                    }
11363                } else {
11364                    trimmed_selections.push(start..end);
11365                }
11366
11367                for trimmed_range in trimmed_selections {
11368                    if is_first {
11369                        is_first = false;
11370                    } else {
11371                        text += "\n";
11372                    }
11373                    let mut len = 0;
11374                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11375                        text.push_str(chunk);
11376                        len += chunk.len();
11377                    }
11378                    clipboard_selections.push(ClipboardSelection {
11379                        len,
11380                        is_entire_line,
11381                        first_line_indent: buffer
11382                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11383                            .len,
11384                    });
11385                }
11386            }
11387        }
11388
11389        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11390            text,
11391            clipboard_selections,
11392        ));
11393    }
11394
11395    pub fn do_paste(
11396        &mut self,
11397        text: &String,
11398        clipboard_selections: Option<Vec<ClipboardSelection>>,
11399        handle_entire_lines: bool,
11400        window: &mut Window,
11401        cx: &mut Context<Self>,
11402    ) {
11403        if self.read_only(cx) {
11404            return;
11405        }
11406
11407        let clipboard_text = Cow::Borrowed(text);
11408
11409        self.transact(window, cx, |this, window, cx| {
11410            if let Some(mut clipboard_selections) = clipboard_selections {
11411                let old_selections = this.selections.all::<usize>(cx);
11412                let all_selections_were_entire_line =
11413                    clipboard_selections.iter().all(|s| s.is_entire_line);
11414                let first_selection_indent_column =
11415                    clipboard_selections.first().map(|s| s.first_line_indent);
11416                if clipboard_selections.len() != old_selections.len() {
11417                    clipboard_selections.drain(..);
11418                }
11419                let cursor_offset = this.selections.last::<usize>(cx).head();
11420                let mut auto_indent_on_paste = true;
11421
11422                this.buffer.update(cx, |buffer, cx| {
11423                    let snapshot = buffer.read(cx);
11424                    auto_indent_on_paste = snapshot
11425                        .language_settings_at(cursor_offset, cx)
11426                        .auto_indent_on_paste;
11427
11428                    let mut start_offset = 0;
11429                    let mut edits = Vec::new();
11430                    let mut original_indent_columns = Vec::new();
11431                    for (ix, selection) in old_selections.iter().enumerate() {
11432                        let to_insert;
11433                        let entire_line;
11434                        let original_indent_column;
11435                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11436                            let end_offset = start_offset + clipboard_selection.len;
11437                            to_insert = &clipboard_text[start_offset..end_offset];
11438                            entire_line = clipboard_selection.is_entire_line;
11439                            start_offset = end_offset + 1;
11440                            original_indent_column = Some(clipboard_selection.first_line_indent);
11441                        } else {
11442                            to_insert = clipboard_text.as_str();
11443                            entire_line = all_selections_were_entire_line;
11444                            original_indent_column = first_selection_indent_column
11445                        }
11446
11447                        // If the corresponding selection was empty when this slice of the
11448                        // clipboard text was written, then the entire line containing the
11449                        // selection was copied. If this selection is also currently empty,
11450                        // then paste the line before the current line of the buffer.
11451                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11452                            let column = selection.start.to_point(&snapshot).column as usize;
11453                            let line_start = selection.start - column;
11454                            line_start..line_start
11455                        } else {
11456                            selection.range()
11457                        };
11458
11459                        edits.push((range, to_insert));
11460                        original_indent_columns.push(original_indent_column);
11461                    }
11462                    drop(snapshot);
11463
11464                    buffer.edit(
11465                        edits,
11466                        if auto_indent_on_paste {
11467                            Some(AutoindentMode::Block {
11468                                original_indent_columns,
11469                            })
11470                        } else {
11471                            None
11472                        },
11473                        cx,
11474                    );
11475                });
11476
11477                let selections = this.selections.all::<usize>(cx);
11478                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11479                    s.select(selections)
11480                });
11481            } else {
11482                this.insert(&clipboard_text, window, cx);
11483            }
11484        });
11485    }
11486
11487    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11488        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11489        if let Some(item) = cx.read_from_clipboard() {
11490            let entries = item.entries();
11491
11492            match entries.first() {
11493                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11494                // of all the pasted entries.
11495                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11496                    .do_paste(
11497                        clipboard_string.text(),
11498                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11499                        true,
11500                        window,
11501                        cx,
11502                    ),
11503                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11504            }
11505        }
11506    }
11507
11508    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11509        if self.read_only(cx) {
11510            return;
11511        }
11512
11513        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11514
11515        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11516            if let Some((selections, _)) =
11517                self.selection_history.transaction(transaction_id).cloned()
11518            {
11519                self.change_selections(None, window, cx, |s| {
11520                    s.select_anchors(selections.to_vec());
11521                });
11522            } else {
11523                log::error!(
11524                    "No entry in selection_history found for undo. \
11525                     This may correspond to a bug where undo does not update the selection. \
11526                     If this is occurring, please add details to \
11527                     https://github.com/zed-industries/zed/issues/22692"
11528                );
11529            }
11530            self.request_autoscroll(Autoscroll::fit(), cx);
11531            self.unmark_text(window, cx);
11532            self.refresh_inline_completion(true, false, window, cx);
11533            cx.emit(EditorEvent::Edited { transaction_id });
11534            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11535        }
11536    }
11537
11538    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11539        if self.read_only(cx) {
11540            return;
11541        }
11542
11543        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11544
11545        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11546            if let Some((_, Some(selections))) =
11547                self.selection_history.transaction(transaction_id).cloned()
11548            {
11549                self.change_selections(None, window, cx, |s| {
11550                    s.select_anchors(selections.to_vec());
11551                });
11552            } else {
11553                log::error!(
11554                    "No entry in selection_history found for redo. \
11555                     This may correspond to a bug where undo does not update the selection. \
11556                     If this is occurring, please add details to \
11557                     https://github.com/zed-industries/zed/issues/22692"
11558                );
11559            }
11560            self.request_autoscroll(Autoscroll::fit(), cx);
11561            self.unmark_text(window, cx);
11562            self.refresh_inline_completion(true, false, window, cx);
11563            cx.emit(EditorEvent::Edited { transaction_id });
11564        }
11565    }
11566
11567    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11568        self.buffer
11569            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11570    }
11571
11572    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11573        self.buffer
11574            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11575    }
11576
11577    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11578        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11579        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11580            s.move_with(|map, selection| {
11581                let cursor = if selection.is_empty() {
11582                    movement::left(map, selection.start)
11583                } else {
11584                    selection.start
11585                };
11586                selection.collapse_to(cursor, SelectionGoal::None);
11587            });
11588        })
11589    }
11590
11591    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11592        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11593        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11594            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11595        })
11596    }
11597
11598    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11599        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11600        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11601            s.move_with(|map, selection| {
11602                let cursor = if selection.is_empty() {
11603                    movement::right(map, selection.end)
11604                } else {
11605                    selection.end
11606                };
11607                selection.collapse_to(cursor, SelectionGoal::None)
11608            });
11609        })
11610    }
11611
11612    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11613        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11614        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11615            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11616        })
11617    }
11618
11619    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11620        if self.take_rename(true, window, cx).is_some() {
11621            return;
11622        }
11623
11624        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11625            cx.propagate();
11626            return;
11627        }
11628
11629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11630
11631        let text_layout_details = &self.text_layout_details(window);
11632        let selection_count = self.selections.count();
11633        let first_selection = self.selections.first_anchor();
11634
11635        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11636            s.move_with(|map, selection| {
11637                if !selection.is_empty() {
11638                    selection.goal = SelectionGoal::None;
11639                }
11640                let (cursor, goal) = movement::up(
11641                    map,
11642                    selection.start,
11643                    selection.goal,
11644                    false,
11645                    text_layout_details,
11646                );
11647                selection.collapse_to(cursor, goal);
11648            });
11649        });
11650
11651        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11652        {
11653            cx.propagate();
11654        }
11655    }
11656
11657    pub fn move_up_by_lines(
11658        &mut self,
11659        action: &MoveUpByLines,
11660        window: &mut Window,
11661        cx: &mut Context<Self>,
11662    ) {
11663        if self.take_rename(true, window, cx).is_some() {
11664            return;
11665        }
11666
11667        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11668            cx.propagate();
11669            return;
11670        }
11671
11672        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11673
11674        let text_layout_details = &self.text_layout_details(window);
11675
11676        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11677            s.move_with(|map, selection| {
11678                if !selection.is_empty() {
11679                    selection.goal = SelectionGoal::None;
11680                }
11681                let (cursor, goal) = movement::up_by_rows(
11682                    map,
11683                    selection.start,
11684                    action.lines,
11685                    selection.goal,
11686                    false,
11687                    text_layout_details,
11688                );
11689                selection.collapse_to(cursor, goal);
11690            });
11691        })
11692    }
11693
11694    pub fn move_down_by_lines(
11695        &mut self,
11696        action: &MoveDownByLines,
11697        window: &mut Window,
11698        cx: &mut Context<Self>,
11699    ) {
11700        if self.take_rename(true, window, cx).is_some() {
11701            return;
11702        }
11703
11704        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11705            cx.propagate();
11706            return;
11707        }
11708
11709        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11710
11711        let text_layout_details = &self.text_layout_details(window);
11712
11713        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11714            s.move_with(|map, selection| {
11715                if !selection.is_empty() {
11716                    selection.goal = SelectionGoal::None;
11717                }
11718                let (cursor, goal) = movement::down_by_rows(
11719                    map,
11720                    selection.start,
11721                    action.lines,
11722                    selection.goal,
11723                    false,
11724                    text_layout_details,
11725                );
11726                selection.collapse_to(cursor, goal);
11727            });
11728        })
11729    }
11730
11731    pub fn select_down_by_lines(
11732        &mut self,
11733        action: &SelectDownByLines,
11734        window: &mut Window,
11735        cx: &mut Context<Self>,
11736    ) {
11737        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11738        let text_layout_details = &self.text_layout_details(window);
11739        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11740            s.move_heads_with(|map, head, goal| {
11741                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11742            })
11743        })
11744    }
11745
11746    pub fn select_up_by_lines(
11747        &mut self,
11748        action: &SelectUpByLines,
11749        window: &mut Window,
11750        cx: &mut Context<Self>,
11751    ) {
11752        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11753        let text_layout_details = &self.text_layout_details(window);
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_heads_with(|map, head, goal| {
11756                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11757            })
11758        })
11759    }
11760
11761    pub fn select_page_up(
11762        &mut self,
11763        _: &SelectPageUp,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        let Some(row_count) = self.visible_row_count() else {
11768            return;
11769        };
11770
11771        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11772
11773        let text_layout_details = &self.text_layout_details(window);
11774
11775        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11776            s.move_heads_with(|map, head, goal| {
11777                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11778            })
11779        })
11780    }
11781
11782    pub fn move_page_up(
11783        &mut self,
11784        action: &MovePageUp,
11785        window: &mut Window,
11786        cx: &mut Context<Self>,
11787    ) {
11788        if self.take_rename(true, window, cx).is_some() {
11789            return;
11790        }
11791
11792        if self
11793            .context_menu
11794            .borrow_mut()
11795            .as_mut()
11796            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11797            .unwrap_or(false)
11798        {
11799            return;
11800        }
11801
11802        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11803            cx.propagate();
11804            return;
11805        }
11806
11807        let Some(row_count) = self.visible_row_count() else {
11808            return;
11809        };
11810
11811        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11812
11813        let autoscroll = if action.center_cursor {
11814            Autoscroll::center()
11815        } else {
11816            Autoscroll::fit()
11817        };
11818
11819        let text_layout_details = &self.text_layout_details(window);
11820
11821        self.change_selections(Some(autoscroll), window, cx, |s| {
11822            s.move_with(|map, selection| {
11823                if !selection.is_empty() {
11824                    selection.goal = SelectionGoal::None;
11825                }
11826                let (cursor, goal) = movement::up_by_rows(
11827                    map,
11828                    selection.end,
11829                    row_count,
11830                    selection.goal,
11831                    false,
11832                    text_layout_details,
11833                );
11834                selection.collapse_to(cursor, goal);
11835            });
11836        });
11837    }
11838
11839    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11840        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11841        let text_layout_details = &self.text_layout_details(window);
11842        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11843            s.move_heads_with(|map, head, goal| {
11844                movement::up(map, head, goal, false, text_layout_details)
11845            })
11846        })
11847    }
11848
11849    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11850        self.take_rename(true, window, cx);
11851
11852        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11853            cx.propagate();
11854            return;
11855        }
11856
11857        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11858
11859        let text_layout_details = &self.text_layout_details(window);
11860        let selection_count = self.selections.count();
11861        let first_selection = self.selections.first_anchor();
11862
11863        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11864            s.move_with(|map, selection| {
11865                if !selection.is_empty() {
11866                    selection.goal = SelectionGoal::None;
11867                }
11868                let (cursor, goal) = movement::down(
11869                    map,
11870                    selection.end,
11871                    selection.goal,
11872                    false,
11873                    text_layout_details,
11874                );
11875                selection.collapse_to(cursor, goal);
11876            });
11877        });
11878
11879        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11880        {
11881            cx.propagate();
11882        }
11883    }
11884
11885    pub fn select_page_down(
11886        &mut self,
11887        _: &SelectPageDown,
11888        window: &mut Window,
11889        cx: &mut Context<Self>,
11890    ) {
11891        let Some(row_count) = self.visible_row_count() else {
11892            return;
11893        };
11894
11895        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11896
11897        let text_layout_details = &self.text_layout_details(window);
11898
11899        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11900            s.move_heads_with(|map, head, goal| {
11901                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11902            })
11903        })
11904    }
11905
11906    pub fn move_page_down(
11907        &mut self,
11908        action: &MovePageDown,
11909        window: &mut Window,
11910        cx: &mut Context<Self>,
11911    ) {
11912        if self.take_rename(true, window, cx).is_some() {
11913            return;
11914        }
11915
11916        if self
11917            .context_menu
11918            .borrow_mut()
11919            .as_mut()
11920            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11921            .unwrap_or(false)
11922        {
11923            return;
11924        }
11925
11926        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11927            cx.propagate();
11928            return;
11929        }
11930
11931        let Some(row_count) = self.visible_row_count() else {
11932            return;
11933        };
11934
11935        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11936
11937        let autoscroll = if action.center_cursor {
11938            Autoscroll::center()
11939        } else {
11940            Autoscroll::fit()
11941        };
11942
11943        let text_layout_details = &self.text_layout_details(window);
11944        self.change_selections(Some(autoscroll), window, cx, |s| {
11945            s.move_with(|map, selection| {
11946                if !selection.is_empty() {
11947                    selection.goal = SelectionGoal::None;
11948                }
11949                let (cursor, goal) = movement::down_by_rows(
11950                    map,
11951                    selection.end,
11952                    row_count,
11953                    selection.goal,
11954                    false,
11955                    text_layout_details,
11956                );
11957                selection.collapse_to(cursor, goal);
11958            });
11959        });
11960    }
11961
11962    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11963        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11964        let text_layout_details = &self.text_layout_details(window);
11965        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11966            s.move_heads_with(|map, head, goal| {
11967                movement::down(map, head, goal, false, text_layout_details)
11968            })
11969        });
11970    }
11971
11972    pub fn context_menu_first(
11973        &mut self,
11974        _: &ContextMenuFirst,
11975        window: &mut Window,
11976        cx: &mut Context<Self>,
11977    ) {
11978        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11979            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11980        }
11981    }
11982
11983    pub fn context_menu_prev(
11984        &mut self,
11985        _: &ContextMenuPrevious,
11986        window: &mut Window,
11987        cx: &mut Context<Self>,
11988    ) {
11989        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11990            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11991        }
11992    }
11993
11994    pub fn context_menu_next(
11995        &mut self,
11996        _: &ContextMenuNext,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12001            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12002        }
12003    }
12004
12005    pub fn context_menu_last(
12006        &mut self,
12007        _: &ContextMenuLast,
12008        window: &mut Window,
12009        cx: &mut Context<Self>,
12010    ) {
12011        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12012            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12013        }
12014    }
12015
12016    pub fn move_to_previous_word_start(
12017        &mut self,
12018        _: &MoveToPreviousWordStart,
12019        window: &mut Window,
12020        cx: &mut Context<Self>,
12021    ) {
12022        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12023        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12024            s.move_cursors_with(|map, head, _| {
12025                (
12026                    movement::previous_word_start(map, head),
12027                    SelectionGoal::None,
12028                )
12029            });
12030        })
12031    }
12032
12033    pub fn move_to_previous_subword_start(
12034        &mut self,
12035        _: &MoveToPreviousSubwordStart,
12036        window: &mut Window,
12037        cx: &mut Context<Self>,
12038    ) {
12039        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12040        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12041            s.move_cursors_with(|map, head, _| {
12042                (
12043                    movement::previous_subword_start(map, head),
12044                    SelectionGoal::None,
12045                )
12046            });
12047        })
12048    }
12049
12050    pub fn select_to_previous_word_start(
12051        &mut self,
12052        _: &SelectToPreviousWordStart,
12053        window: &mut Window,
12054        cx: &mut Context<Self>,
12055    ) {
12056        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12057        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12058            s.move_heads_with(|map, head, _| {
12059                (
12060                    movement::previous_word_start(map, head),
12061                    SelectionGoal::None,
12062                )
12063            });
12064        })
12065    }
12066
12067    pub fn select_to_previous_subword_start(
12068        &mut self,
12069        _: &SelectToPreviousSubwordStart,
12070        window: &mut Window,
12071        cx: &mut Context<Self>,
12072    ) {
12073        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12074        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12075            s.move_heads_with(|map, head, _| {
12076                (
12077                    movement::previous_subword_start(map, head),
12078                    SelectionGoal::None,
12079                )
12080            });
12081        })
12082    }
12083
12084    pub fn delete_to_previous_word_start(
12085        &mut self,
12086        action: &DeleteToPreviousWordStart,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12091        self.transact(window, cx, |this, window, cx| {
12092            this.select_autoclose_pair(window, cx);
12093            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12094                s.move_with(|map, selection| {
12095                    if selection.is_empty() {
12096                        let cursor = if action.ignore_newlines {
12097                            movement::previous_word_start(map, selection.head())
12098                        } else {
12099                            movement::previous_word_start_or_newline(map, selection.head())
12100                        };
12101                        selection.set_head(cursor, SelectionGoal::None);
12102                    }
12103                });
12104            });
12105            this.insert("", window, cx);
12106        });
12107    }
12108
12109    pub fn delete_to_previous_subword_start(
12110        &mut self,
12111        _: &DeleteToPreviousSubwordStart,
12112        window: &mut Window,
12113        cx: &mut Context<Self>,
12114    ) {
12115        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12116        self.transact(window, cx, |this, window, cx| {
12117            this.select_autoclose_pair(window, cx);
12118            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12119                s.move_with(|map, selection| {
12120                    if selection.is_empty() {
12121                        let cursor = movement::previous_subword_start(map, selection.head());
12122                        selection.set_head(cursor, SelectionGoal::None);
12123                    }
12124                });
12125            });
12126            this.insert("", window, cx);
12127        });
12128    }
12129
12130    pub fn move_to_next_word_end(
12131        &mut self,
12132        _: &MoveToNextWordEnd,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12137        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12138            s.move_cursors_with(|map, head, _| {
12139                (movement::next_word_end(map, head), SelectionGoal::None)
12140            });
12141        })
12142    }
12143
12144    pub fn move_to_next_subword_end(
12145        &mut self,
12146        _: &MoveToNextSubwordEnd,
12147        window: &mut Window,
12148        cx: &mut Context<Self>,
12149    ) {
12150        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12151        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12152            s.move_cursors_with(|map, head, _| {
12153                (movement::next_subword_end(map, head), SelectionGoal::None)
12154            });
12155        })
12156    }
12157
12158    pub fn select_to_next_word_end(
12159        &mut self,
12160        _: &SelectToNextWordEnd,
12161        window: &mut Window,
12162        cx: &mut Context<Self>,
12163    ) {
12164        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12165        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12166            s.move_heads_with(|map, head, _| {
12167                (movement::next_word_end(map, head), SelectionGoal::None)
12168            });
12169        })
12170    }
12171
12172    pub fn select_to_next_subword_end(
12173        &mut self,
12174        _: &SelectToNextSubwordEnd,
12175        window: &mut Window,
12176        cx: &mut Context<Self>,
12177    ) {
12178        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12179        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12180            s.move_heads_with(|map, head, _| {
12181                (movement::next_subword_end(map, head), SelectionGoal::None)
12182            });
12183        })
12184    }
12185
12186    pub fn delete_to_next_word_end(
12187        &mut self,
12188        action: &DeleteToNextWordEnd,
12189        window: &mut Window,
12190        cx: &mut Context<Self>,
12191    ) {
12192        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12193        self.transact(window, cx, |this, window, cx| {
12194            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12195                s.move_with(|map, selection| {
12196                    if selection.is_empty() {
12197                        let cursor = if action.ignore_newlines {
12198                            movement::next_word_end(map, selection.head())
12199                        } else {
12200                            movement::next_word_end_or_newline(map, selection.head())
12201                        };
12202                        selection.set_head(cursor, SelectionGoal::None);
12203                    }
12204                });
12205            });
12206            this.insert("", window, cx);
12207        });
12208    }
12209
12210    pub fn delete_to_next_subword_end(
12211        &mut self,
12212        _: &DeleteToNextSubwordEnd,
12213        window: &mut Window,
12214        cx: &mut Context<Self>,
12215    ) {
12216        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12217        self.transact(window, cx, |this, window, cx| {
12218            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12219                s.move_with(|map, selection| {
12220                    if selection.is_empty() {
12221                        let cursor = movement::next_subword_end(map, selection.head());
12222                        selection.set_head(cursor, SelectionGoal::None);
12223                    }
12224                });
12225            });
12226            this.insert("", window, cx);
12227        });
12228    }
12229
12230    pub fn move_to_beginning_of_line(
12231        &mut self,
12232        action: &MoveToBeginningOfLine,
12233        window: &mut Window,
12234        cx: &mut Context<Self>,
12235    ) {
12236        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12237        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12238            s.move_cursors_with(|map, head, _| {
12239                (
12240                    movement::indented_line_beginning(
12241                        map,
12242                        head,
12243                        action.stop_at_soft_wraps,
12244                        action.stop_at_indent,
12245                    ),
12246                    SelectionGoal::None,
12247                )
12248            });
12249        })
12250    }
12251
12252    pub fn select_to_beginning_of_line(
12253        &mut self,
12254        action: &SelectToBeginningOfLine,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12259        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12260            s.move_heads_with(|map, head, _| {
12261                (
12262                    movement::indented_line_beginning(
12263                        map,
12264                        head,
12265                        action.stop_at_soft_wraps,
12266                        action.stop_at_indent,
12267                    ),
12268                    SelectionGoal::None,
12269                )
12270            });
12271        });
12272    }
12273
12274    pub fn delete_to_beginning_of_line(
12275        &mut self,
12276        action: &DeleteToBeginningOfLine,
12277        window: &mut Window,
12278        cx: &mut Context<Self>,
12279    ) {
12280        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12281        self.transact(window, cx, |this, window, cx| {
12282            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12283                s.move_with(|_, selection| {
12284                    selection.reversed = true;
12285                });
12286            });
12287
12288            this.select_to_beginning_of_line(
12289                &SelectToBeginningOfLine {
12290                    stop_at_soft_wraps: false,
12291                    stop_at_indent: action.stop_at_indent,
12292                },
12293                window,
12294                cx,
12295            );
12296            this.backspace(&Backspace, window, cx);
12297        });
12298    }
12299
12300    pub fn move_to_end_of_line(
12301        &mut self,
12302        action: &MoveToEndOfLine,
12303        window: &mut Window,
12304        cx: &mut Context<Self>,
12305    ) {
12306        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12307        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12308            s.move_cursors_with(|map, head, _| {
12309                (
12310                    movement::line_end(map, head, action.stop_at_soft_wraps),
12311                    SelectionGoal::None,
12312                )
12313            });
12314        })
12315    }
12316
12317    pub fn select_to_end_of_line(
12318        &mut self,
12319        action: &SelectToEndOfLine,
12320        window: &mut Window,
12321        cx: &mut Context<Self>,
12322    ) {
12323        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12324        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12325            s.move_heads_with(|map, head, _| {
12326                (
12327                    movement::line_end(map, head, action.stop_at_soft_wraps),
12328                    SelectionGoal::None,
12329                )
12330            });
12331        })
12332    }
12333
12334    pub fn delete_to_end_of_line(
12335        &mut self,
12336        _: &DeleteToEndOfLine,
12337        window: &mut Window,
12338        cx: &mut Context<Self>,
12339    ) {
12340        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12341        self.transact(window, cx, |this, window, cx| {
12342            this.select_to_end_of_line(
12343                &SelectToEndOfLine {
12344                    stop_at_soft_wraps: false,
12345                },
12346                window,
12347                cx,
12348            );
12349            this.delete(&Delete, window, cx);
12350        });
12351    }
12352
12353    pub fn cut_to_end_of_line(
12354        &mut self,
12355        _: &CutToEndOfLine,
12356        window: &mut Window,
12357        cx: &mut Context<Self>,
12358    ) {
12359        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12360        self.transact(window, cx, |this, window, cx| {
12361            this.select_to_end_of_line(
12362                &SelectToEndOfLine {
12363                    stop_at_soft_wraps: false,
12364                },
12365                window,
12366                cx,
12367            );
12368            this.cut(&Cut, window, cx);
12369        });
12370    }
12371
12372    pub fn move_to_start_of_paragraph(
12373        &mut self,
12374        _: &MoveToStartOfParagraph,
12375        window: &mut Window,
12376        cx: &mut Context<Self>,
12377    ) {
12378        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12379            cx.propagate();
12380            return;
12381        }
12382        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12383        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12384            s.move_with(|map, selection| {
12385                selection.collapse_to(
12386                    movement::start_of_paragraph(map, selection.head(), 1),
12387                    SelectionGoal::None,
12388                )
12389            });
12390        })
12391    }
12392
12393    pub fn move_to_end_of_paragraph(
12394        &mut self,
12395        _: &MoveToEndOfParagraph,
12396        window: &mut Window,
12397        cx: &mut Context<Self>,
12398    ) {
12399        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12400            cx.propagate();
12401            return;
12402        }
12403        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12405            s.move_with(|map, selection| {
12406                selection.collapse_to(
12407                    movement::end_of_paragraph(map, selection.head(), 1),
12408                    SelectionGoal::None,
12409                )
12410            });
12411        })
12412    }
12413
12414    pub fn select_to_start_of_paragraph(
12415        &mut self,
12416        _: &SelectToStartOfParagraph,
12417        window: &mut Window,
12418        cx: &mut Context<Self>,
12419    ) {
12420        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12421            cx.propagate();
12422            return;
12423        }
12424        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12425        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12426            s.move_heads_with(|map, head, _| {
12427                (
12428                    movement::start_of_paragraph(map, head, 1),
12429                    SelectionGoal::None,
12430                )
12431            });
12432        })
12433    }
12434
12435    pub fn select_to_end_of_paragraph(
12436        &mut self,
12437        _: &SelectToEndOfParagraph,
12438        window: &mut Window,
12439        cx: &mut Context<Self>,
12440    ) {
12441        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12442            cx.propagate();
12443            return;
12444        }
12445        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12446        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12447            s.move_heads_with(|map, head, _| {
12448                (
12449                    movement::end_of_paragraph(map, head, 1),
12450                    SelectionGoal::None,
12451                )
12452            });
12453        })
12454    }
12455
12456    pub fn move_to_start_of_excerpt(
12457        &mut self,
12458        _: &MoveToStartOfExcerpt,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12463            cx.propagate();
12464            return;
12465        }
12466        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12467        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12468            s.move_with(|map, selection| {
12469                selection.collapse_to(
12470                    movement::start_of_excerpt(
12471                        map,
12472                        selection.head(),
12473                        workspace::searchable::Direction::Prev,
12474                    ),
12475                    SelectionGoal::None,
12476                )
12477            });
12478        })
12479    }
12480
12481    pub fn move_to_start_of_next_excerpt(
12482        &mut self,
12483        _: &MoveToStartOfNextExcerpt,
12484        window: &mut Window,
12485        cx: &mut Context<Self>,
12486    ) {
12487        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12488            cx.propagate();
12489            return;
12490        }
12491
12492        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12493            s.move_with(|map, selection| {
12494                selection.collapse_to(
12495                    movement::start_of_excerpt(
12496                        map,
12497                        selection.head(),
12498                        workspace::searchable::Direction::Next,
12499                    ),
12500                    SelectionGoal::None,
12501                )
12502            });
12503        })
12504    }
12505
12506    pub fn move_to_end_of_excerpt(
12507        &mut self,
12508        _: &MoveToEndOfExcerpt,
12509        window: &mut Window,
12510        cx: &mut Context<Self>,
12511    ) {
12512        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12513            cx.propagate();
12514            return;
12515        }
12516        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12517        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12518            s.move_with(|map, selection| {
12519                selection.collapse_to(
12520                    movement::end_of_excerpt(
12521                        map,
12522                        selection.head(),
12523                        workspace::searchable::Direction::Next,
12524                    ),
12525                    SelectionGoal::None,
12526                )
12527            });
12528        })
12529    }
12530
12531    pub fn move_to_end_of_previous_excerpt(
12532        &mut self,
12533        _: &MoveToEndOfPreviousExcerpt,
12534        window: &mut Window,
12535        cx: &mut Context<Self>,
12536    ) {
12537        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12538            cx.propagate();
12539            return;
12540        }
12541        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12542        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12543            s.move_with(|map, selection| {
12544                selection.collapse_to(
12545                    movement::end_of_excerpt(
12546                        map,
12547                        selection.head(),
12548                        workspace::searchable::Direction::Prev,
12549                    ),
12550                    SelectionGoal::None,
12551                )
12552            });
12553        })
12554    }
12555
12556    pub fn select_to_start_of_excerpt(
12557        &mut self,
12558        _: &SelectToStartOfExcerpt,
12559        window: &mut Window,
12560        cx: &mut Context<Self>,
12561    ) {
12562        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12563            cx.propagate();
12564            return;
12565        }
12566        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12567        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12568            s.move_heads_with(|map, head, _| {
12569                (
12570                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12571                    SelectionGoal::None,
12572                )
12573            });
12574        })
12575    }
12576
12577    pub fn select_to_start_of_next_excerpt(
12578        &mut self,
12579        _: &SelectToStartOfNextExcerpt,
12580        window: &mut Window,
12581        cx: &mut Context<Self>,
12582    ) {
12583        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12584            cx.propagate();
12585            return;
12586        }
12587        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12588        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12589            s.move_heads_with(|map, head, _| {
12590                (
12591                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12592                    SelectionGoal::None,
12593                )
12594            });
12595        })
12596    }
12597
12598    pub fn select_to_end_of_excerpt(
12599        &mut self,
12600        _: &SelectToEndOfExcerpt,
12601        window: &mut Window,
12602        cx: &mut Context<Self>,
12603    ) {
12604        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12605            cx.propagate();
12606            return;
12607        }
12608        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12609        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12610            s.move_heads_with(|map, head, _| {
12611                (
12612                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12613                    SelectionGoal::None,
12614                )
12615            });
12616        })
12617    }
12618
12619    pub fn select_to_end_of_previous_excerpt(
12620        &mut self,
12621        _: &SelectToEndOfPreviousExcerpt,
12622        window: &mut Window,
12623        cx: &mut Context<Self>,
12624    ) {
12625        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12626            cx.propagate();
12627            return;
12628        }
12629        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12631            s.move_heads_with(|map, head, _| {
12632                (
12633                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12634                    SelectionGoal::None,
12635                )
12636            });
12637        })
12638    }
12639
12640    pub fn move_to_beginning(
12641        &mut self,
12642        _: &MoveToBeginning,
12643        window: &mut Window,
12644        cx: &mut Context<Self>,
12645    ) {
12646        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12647            cx.propagate();
12648            return;
12649        }
12650        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12651        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12652            s.select_ranges(vec![0..0]);
12653        });
12654    }
12655
12656    pub fn select_to_beginning(
12657        &mut self,
12658        _: &SelectToBeginning,
12659        window: &mut Window,
12660        cx: &mut Context<Self>,
12661    ) {
12662        let mut selection = self.selections.last::<Point>(cx);
12663        selection.set_head(Point::zero(), SelectionGoal::None);
12664        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12665        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12666            s.select(vec![selection]);
12667        });
12668    }
12669
12670    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12671        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12672            cx.propagate();
12673            return;
12674        }
12675        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12676        let cursor = self.buffer.read(cx).read(cx).len();
12677        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12678            s.select_ranges(vec![cursor..cursor])
12679        });
12680    }
12681
12682    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12683        self.nav_history = nav_history;
12684    }
12685
12686    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12687        self.nav_history.as_ref()
12688    }
12689
12690    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12691        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12692    }
12693
12694    fn push_to_nav_history(
12695        &mut self,
12696        cursor_anchor: Anchor,
12697        new_position: Option<Point>,
12698        is_deactivate: bool,
12699        cx: &mut Context<Self>,
12700    ) {
12701        if let Some(nav_history) = self.nav_history.as_mut() {
12702            let buffer = self.buffer.read(cx).read(cx);
12703            let cursor_position = cursor_anchor.to_point(&buffer);
12704            let scroll_state = self.scroll_manager.anchor();
12705            let scroll_top_row = scroll_state.top_row(&buffer);
12706            drop(buffer);
12707
12708            if let Some(new_position) = new_position {
12709                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12710                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12711                    return;
12712                }
12713            }
12714
12715            nav_history.push(
12716                Some(NavigationData {
12717                    cursor_anchor,
12718                    cursor_position,
12719                    scroll_anchor: scroll_state,
12720                    scroll_top_row,
12721                }),
12722                cx,
12723            );
12724            cx.emit(EditorEvent::PushedToNavHistory {
12725                anchor: cursor_anchor,
12726                is_deactivate,
12727            })
12728        }
12729    }
12730
12731    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12732        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12733        let buffer = self.buffer.read(cx).snapshot(cx);
12734        let mut selection = self.selections.first::<usize>(cx);
12735        selection.set_head(buffer.len(), SelectionGoal::None);
12736        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12737            s.select(vec![selection]);
12738        });
12739    }
12740
12741    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12742        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12743        let end = self.buffer.read(cx).read(cx).len();
12744        self.change_selections(None, window, cx, |s| {
12745            s.select_ranges(vec![0..end]);
12746        });
12747    }
12748
12749    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12750        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12751        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12752        let mut selections = self.selections.all::<Point>(cx);
12753        let max_point = display_map.buffer_snapshot.max_point();
12754        for selection in &mut selections {
12755            let rows = selection.spanned_rows(true, &display_map);
12756            selection.start = Point::new(rows.start.0, 0);
12757            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12758            selection.reversed = false;
12759        }
12760        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12761            s.select(selections);
12762        });
12763    }
12764
12765    pub fn split_selection_into_lines(
12766        &mut self,
12767        _: &SplitSelectionIntoLines,
12768        window: &mut Window,
12769        cx: &mut Context<Self>,
12770    ) {
12771        let selections = self
12772            .selections
12773            .all::<Point>(cx)
12774            .into_iter()
12775            .map(|selection| selection.start..selection.end)
12776            .collect::<Vec<_>>();
12777        self.unfold_ranges(&selections, true, true, cx);
12778
12779        let mut new_selection_ranges = Vec::new();
12780        {
12781            let buffer = self.buffer.read(cx).read(cx);
12782            for selection in selections {
12783                for row in selection.start.row..selection.end.row {
12784                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12785                    new_selection_ranges.push(cursor..cursor);
12786                }
12787
12788                let is_multiline_selection = selection.start.row != selection.end.row;
12789                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12790                // so this action feels more ergonomic when paired with other selection operations
12791                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12792                if !should_skip_last {
12793                    new_selection_ranges.push(selection.end..selection.end);
12794                }
12795            }
12796        }
12797        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12798            s.select_ranges(new_selection_ranges);
12799        });
12800    }
12801
12802    pub fn add_selection_above(
12803        &mut self,
12804        _: &AddSelectionAbove,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        self.add_selection(true, window, cx);
12809    }
12810
12811    pub fn add_selection_below(
12812        &mut self,
12813        _: &AddSelectionBelow,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        self.add_selection(false, window, cx);
12818    }
12819
12820    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12821        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12822
12823        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12824        let all_selections = self.selections.all::<Point>(cx);
12825        let text_layout_details = self.text_layout_details(window);
12826
12827        let (mut columnar_selections, new_selections_to_columnarize) = {
12828            if let Some(state) = self.add_selections_state.as_ref() {
12829                let columnar_selection_ids: HashSet<_> = state
12830                    .groups
12831                    .iter()
12832                    .flat_map(|group| group.stack.iter())
12833                    .copied()
12834                    .collect();
12835
12836                all_selections
12837                    .into_iter()
12838                    .partition(|s| columnar_selection_ids.contains(&s.id))
12839            } else {
12840                (Vec::new(), all_selections)
12841            }
12842        };
12843
12844        let mut state = self
12845            .add_selections_state
12846            .take()
12847            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
12848
12849        for selection in new_selections_to_columnarize {
12850            let range = selection.display_range(&display_map).sorted();
12851            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12852            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12853            let positions = start_x.min(end_x)..start_x.max(end_x);
12854            let mut stack = Vec::new();
12855            for row in range.start.row().0..=range.end.row().0 {
12856                if let Some(selection) = self.selections.build_columnar_selection(
12857                    &display_map,
12858                    DisplayRow(row),
12859                    &positions,
12860                    selection.reversed,
12861                    &text_layout_details,
12862                ) {
12863                    stack.push(selection.id);
12864                    columnar_selections.push(selection);
12865                }
12866            }
12867            if !stack.is_empty() {
12868                if above {
12869                    stack.reverse();
12870                }
12871                state.groups.push(AddSelectionsGroup { above, stack });
12872            }
12873        }
12874
12875        let mut final_selections = Vec::new();
12876        let end_row = if above {
12877            DisplayRow(0)
12878        } else {
12879            display_map.max_point().row()
12880        };
12881
12882        let mut last_added_item_per_group = HashMap::default();
12883        for group in state.groups.iter_mut() {
12884            if let Some(last_id) = group.stack.last() {
12885                last_added_item_per_group.insert(*last_id, group);
12886            }
12887        }
12888
12889        for selection in columnar_selections {
12890            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
12891                if above == group.above {
12892                    let range = selection.display_range(&display_map).sorted();
12893                    debug_assert_eq!(range.start.row(), range.end.row());
12894                    let mut row = range.start.row();
12895                    let positions =
12896                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12897                            px(start)..px(end)
12898                        } else {
12899                            let start_x =
12900                                display_map.x_for_display_point(range.start, &text_layout_details);
12901                            let end_x =
12902                                display_map.x_for_display_point(range.end, &text_layout_details);
12903                            start_x.min(end_x)..start_x.max(end_x)
12904                        };
12905
12906                    let mut maybe_new_selection = None;
12907                    while row != end_row {
12908                        if above {
12909                            row.0 -= 1;
12910                        } else {
12911                            row.0 += 1;
12912                        }
12913                        if let Some(new_selection) = self.selections.build_columnar_selection(
12914                            &display_map,
12915                            row,
12916                            &positions,
12917                            selection.reversed,
12918                            &text_layout_details,
12919                        ) {
12920                            maybe_new_selection = Some(new_selection);
12921                            break;
12922                        }
12923                    }
12924
12925                    if let Some(new_selection) = maybe_new_selection {
12926                        group.stack.push(new_selection.id);
12927                        if above {
12928                            final_selections.push(new_selection);
12929                            final_selections.push(selection);
12930                        } else {
12931                            final_selections.push(selection);
12932                            final_selections.push(new_selection);
12933                        }
12934                    } else {
12935                        final_selections.push(selection);
12936                    }
12937                } else {
12938                    group.stack.pop();
12939                }
12940            } else {
12941                final_selections.push(selection);
12942            }
12943        }
12944
12945        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12946            s.select(final_selections);
12947        });
12948
12949        let final_selection_ids: HashSet<_> = self
12950            .selections
12951            .all::<Point>(cx)
12952            .iter()
12953            .map(|s| s.id)
12954            .collect();
12955        state.groups.retain_mut(|group| {
12956            // selections might get merged above so we remove invalid items from stacks
12957            group.stack.retain(|id| final_selection_ids.contains(id));
12958
12959            // single selection in stack can be treated as initial state
12960            group.stack.len() > 1
12961        });
12962
12963        if !state.groups.is_empty() {
12964            self.add_selections_state = Some(state);
12965        }
12966    }
12967
12968    fn select_match_ranges(
12969        &mut self,
12970        range: Range<usize>,
12971        reversed: bool,
12972        replace_newest: bool,
12973        auto_scroll: Option<Autoscroll>,
12974        window: &mut Window,
12975        cx: &mut Context<Editor>,
12976    ) {
12977        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12978        self.change_selections(auto_scroll, window, cx, |s| {
12979            if replace_newest {
12980                s.delete(s.newest_anchor().id);
12981            }
12982            if reversed {
12983                s.insert_range(range.end..range.start);
12984            } else {
12985                s.insert_range(range);
12986            }
12987        });
12988    }
12989
12990    pub fn select_next_match_internal(
12991        &mut self,
12992        display_map: &DisplaySnapshot,
12993        replace_newest: bool,
12994        autoscroll: Option<Autoscroll>,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) -> Result<()> {
12998        let buffer = &display_map.buffer_snapshot;
12999        let mut selections = self.selections.all::<usize>(cx);
13000        if let Some(mut select_next_state) = self.select_next_state.take() {
13001            let query = &select_next_state.query;
13002            if !select_next_state.done {
13003                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13004                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13005                let mut next_selected_range = None;
13006
13007                let bytes_after_last_selection =
13008                    buffer.bytes_in_range(last_selection.end..buffer.len());
13009                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13010                let query_matches = query
13011                    .stream_find_iter(bytes_after_last_selection)
13012                    .map(|result| (last_selection.end, result))
13013                    .chain(
13014                        query
13015                            .stream_find_iter(bytes_before_first_selection)
13016                            .map(|result| (0, result)),
13017                    );
13018
13019                for (start_offset, query_match) in query_matches {
13020                    let query_match = query_match.unwrap(); // can only fail due to I/O
13021                    let offset_range =
13022                        start_offset + query_match.start()..start_offset + query_match.end();
13023                    let display_range = offset_range.start.to_display_point(display_map)
13024                        ..offset_range.end.to_display_point(display_map);
13025
13026                    if !select_next_state.wordwise
13027                        || (!movement::is_inside_word(display_map, display_range.start)
13028                            && !movement::is_inside_word(display_map, display_range.end))
13029                    {
13030                        // TODO: This is n^2, because we might check all the selections
13031                        if !selections
13032                            .iter()
13033                            .any(|selection| selection.range().overlaps(&offset_range))
13034                        {
13035                            next_selected_range = Some(offset_range);
13036                            break;
13037                        }
13038                    }
13039                }
13040
13041                if let Some(next_selected_range) = next_selected_range {
13042                    self.select_match_ranges(
13043                        next_selected_range,
13044                        last_selection.reversed,
13045                        replace_newest,
13046                        autoscroll,
13047                        window,
13048                        cx,
13049                    );
13050                } else {
13051                    select_next_state.done = true;
13052                }
13053            }
13054
13055            self.select_next_state = Some(select_next_state);
13056        } else {
13057            let mut only_carets = true;
13058            let mut same_text_selected = true;
13059            let mut selected_text = None;
13060
13061            let mut selections_iter = selections.iter().peekable();
13062            while let Some(selection) = selections_iter.next() {
13063                if selection.start != selection.end {
13064                    only_carets = false;
13065                }
13066
13067                if same_text_selected {
13068                    if selected_text.is_none() {
13069                        selected_text =
13070                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13071                    }
13072
13073                    if let Some(next_selection) = selections_iter.peek() {
13074                        if next_selection.range().len() == selection.range().len() {
13075                            let next_selected_text = buffer
13076                                .text_for_range(next_selection.range())
13077                                .collect::<String>();
13078                            if Some(next_selected_text) != selected_text {
13079                                same_text_selected = false;
13080                                selected_text = None;
13081                            }
13082                        } else {
13083                            same_text_selected = false;
13084                            selected_text = None;
13085                        }
13086                    }
13087                }
13088            }
13089
13090            if only_carets {
13091                for selection in &mut selections {
13092                    let word_range = movement::surrounding_word(
13093                        display_map,
13094                        selection.start.to_display_point(display_map),
13095                    );
13096                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
13097                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
13098                    selection.goal = SelectionGoal::None;
13099                    selection.reversed = false;
13100                    self.select_match_ranges(
13101                        selection.start..selection.end,
13102                        selection.reversed,
13103                        replace_newest,
13104                        autoscroll,
13105                        window,
13106                        cx,
13107                    );
13108                }
13109
13110                if selections.len() == 1 {
13111                    let selection = selections
13112                        .last()
13113                        .expect("ensured that there's only one selection");
13114                    let query = buffer
13115                        .text_for_range(selection.start..selection.end)
13116                        .collect::<String>();
13117                    let is_empty = query.is_empty();
13118                    let select_state = SelectNextState {
13119                        query: AhoCorasick::new(&[query])?,
13120                        wordwise: true,
13121                        done: is_empty,
13122                    };
13123                    self.select_next_state = Some(select_state);
13124                } else {
13125                    self.select_next_state = None;
13126                }
13127            } else if let Some(selected_text) = selected_text {
13128                self.select_next_state = Some(SelectNextState {
13129                    query: AhoCorasick::new(&[selected_text])?,
13130                    wordwise: false,
13131                    done: false,
13132                });
13133                self.select_next_match_internal(
13134                    display_map,
13135                    replace_newest,
13136                    autoscroll,
13137                    window,
13138                    cx,
13139                )?;
13140            }
13141        }
13142        Ok(())
13143    }
13144
13145    pub fn select_all_matches(
13146        &mut self,
13147        _action: &SelectAllMatches,
13148        window: &mut Window,
13149        cx: &mut Context<Self>,
13150    ) -> Result<()> {
13151        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13152
13153        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13154
13155        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13156        let Some(select_next_state) = self.select_next_state.as_mut() else {
13157            return Ok(());
13158        };
13159        if select_next_state.done {
13160            return Ok(());
13161        }
13162
13163        let mut new_selections = Vec::new();
13164
13165        let reversed = self.selections.oldest::<usize>(cx).reversed;
13166        let buffer = &display_map.buffer_snapshot;
13167        let query_matches = select_next_state
13168            .query
13169            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13170
13171        for query_match in query_matches.into_iter() {
13172            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13173            let offset_range = if reversed {
13174                query_match.end()..query_match.start()
13175            } else {
13176                query_match.start()..query_match.end()
13177            };
13178            let display_range = offset_range.start.to_display_point(&display_map)
13179                ..offset_range.end.to_display_point(&display_map);
13180
13181            if !select_next_state.wordwise
13182                || (!movement::is_inside_word(&display_map, display_range.start)
13183                    && !movement::is_inside_word(&display_map, display_range.end))
13184            {
13185                new_selections.push(offset_range.start..offset_range.end);
13186            }
13187        }
13188
13189        select_next_state.done = true;
13190        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13191        self.change_selections(None, window, cx, |selections| {
13192            selections.select_ranges(new_selections)
13193        });
13194
13195        Ok(())
13196    }
13197
13198    pub fn select_next(
13199        &mut self,
13200        action: &SelectNext,
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        self.select_next_match_internal(
13207            &display_map,
13208            action.replace_newest,
13209            Some(Autoscroll::newest()),
13210            window,
13211            cx,
13212        )?;
13213        Ok(())
13214    }
13215
13216    pub fn select_previous(
13217        &mut self,
13218        action: &SelectPrevious,
13219        window: &mut Window,
13220        cx: &mut Context<Self>,
13221    ) -> Result<()> {
13222        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13223        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13224        let buffer = &display_map.buffer_snapshot;
13225        let mut selections = self.selections.all::<usize>(cx);
13226        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13227            let query = &select_prev_state.query;
13228            if !select_prev_state.done {
13229                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13230                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13231                let mut next_selected_range = None;
13232                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13233                let bytes_before_last_selection =
13234                    buffer.reversed_bytes_in_range(0..last_selection.start);
13235                let bytes_after_first_selection =
13236                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13237                let query_matches = query
13238                    .stream_find_iter(bytes_before_last_selection)
13239                    .map(|result| (last_selection.start, result))
13240                    .chain(
13241                        query
13242                            .stream_find_iter(bytes_after_first_selection)
13243                            .map(|result| (buffer.len(), result)),
13244                    );
13245                for (end_offset, query_match) in query_matches {
13246                    let query_match = query_match.unwrap(); // can only fail due to I/O
13247                    let offset_range =
13248                        end_offset - query_match.end()..end_offset - query_match.start();
13249                    let display_range = offset_range.start.to_display_point(&display_map)
13250                        ..offset_range.end.to_display_point(&display_map);
13251
13252                    if !select_prev_state.wordwise
13253                        || (!movement::is_inside_word(&display_map, display_range.start)
13254                            && !movement::is_inside_word(&display_map, display_range.end))
13255                    {
13256                        next_selected_range = Some(offset_range);
13257                        break;
13258                    }
13259                }
13260
13261                if let Some(next_selected_range) = next_selected_range {
13262                    self.select_match_ranges(
13263                        next_selected_range,
13264                        last_selection.reversed,
13265                        action.replace_newest,
13266                        Some(Autoscroll::newest()),
13267                        window,
13268                        cx,
13269                    );
13270                } else {
13271                    select_prev_state.done = true;
13272                }
13273            }
13274
13275            self.select_prev_state = Some(select_prev_state);
13276        } else {
13277            let mut only_carets = true;
13278            let mut same_text_selected = true;
13279            let mut selected_text = None;
13280
13281            let mut selections_iter = selections.iter().peekable();
13282            while let Some(selection) = selections_iter.next() {
13283                if selection.start != selection.end {
13284                    only_carets = false;
13285                }
13286
13287                if same_text_selected {
13288                    if selected_text.is_none() {
13289                        selected_text =
13290                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13291                    }
13292
13293                    if let Some(next_selection) = selections_iter.peek() {
13294                        if next_selection.range().len() == selection.range().len() {
13295                            let next_selected_text = buffer
13296                                .text_for_range(next_selection.range())
13297                                .collect::<String>();
13298                            if Some(next_selected_text) != selected_text {
13299                                same_text_selected = false;
13300                                selected_text = None;
13301                            }
13302                        } else {
13303                            same_text_selected = false;
13304                            selected_text = None;
13305                        }
13306                    }
13307                }
13308            }
13309
13310            if only_carets {
13311                for selection in &mut selections {
13312                    let word_range = movement::surrounding_word(
13313                        &display_map,
13314                        selection.start.to_display_point(&display_map),
13315                    );
13316                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13317                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13318                    selection.goal = SelectionGoal::None;
13319                    selection.reversed = false;
13320                    self.select_match_ranges(
13321                        selection.start..selection.end,
13322                        selection.reversed,
13323                        action.replace_newest,
13324                        Some(Autoscroll::newest()),
13325                        window,
13326                        cx,
13327                    );
13328                }
13329                if selections.len() == 1 {
13330                    let selection = selections
13331                        .last()
13332                        .expect("ensured that there's only one selection");
13333                    let query = buffer
13334                        .text_for_range(selection.start..selection.end)
13335                        .collect::<String>();
13336                    let is_empty = query.is_empty();
13337                    let select_state = SelectNextState {
13338                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13339                        wordwise: true,
13340                        done: is_empty,
13341                    };
13342                    self.select_prev_state = Some(select_state);
13343                } else {
13344                    self.select_prev_state = None;
13345                }
13346            } else if let Some(selected_text) = selected_text {
13347                self.select_prev_state = Some(SelectNextState {
13348                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13349                    wordwise: false,
13350                    done: false,
13351                });
13352                self.select_previous(action, window, cx)?;
13353            }
13354        }
13355        Ok(())
13356    }
13357
13358    pub fn find_next_match(
13359        &mut self,
13360        _: &FindNextMatch,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) -> Result<()> {
13364        let selections = self.selections.disjoint_anchors();
13365        match selections.first() {
13366            Some(first) if selections.len() >= 2 => {
13367                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13368                    s.select_ranges([first.range()]);
13369                });
13370            }
13371            _ => self.select_next(
13372                &SelectNext {
13373                    replace_newest: true,
13374                },
13375                window,
13376                cx,
13377            )?,
13378        }
13379        Ok(())
13380    }
13381
13382    pub fn find_previous_match(
13383        &mut self,
13384        _: &FindPreviousMatch,
13385        window: &mut Window,
13386        cx: &mut Context<Self>,
13387    ) -> Result<()> {
13388        let selections = self.selections.disjoint_anchors();
13389        match selections.last() {
13390            Some(last) if selections.len() >= 2 => {
13391                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13392                    s.select_ranges([last.range()]);
13393                });
13394            }
13395            _ => self.select_previous(
13396                &SelectPrevious {
13397                    replace_newest: true,
13398                },
13399                window,
13400                cx,
13401            )?,
13402        }
13403        Ok(())
13404    }
13405
13406    pub fn toggle_comments(
13407        &mut self,
13408        action: &ToggleComments,
13409        window: &mut Window,
13410        cx: &mut Context<Self>,
13411    ) {
13412        if self.read_only(cx) {
13413            return;
13414        }
13415        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13416        let text_layout_details = &self.text_layout_details(window);
13417        self.transact(window, cx, |this, window, cx| {
13418            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13419            let mut edits = Vec::new();
13420            let mut selection_edit_ranges = Vec::new();
13421            let mut last_toggled_row = None;
13422            let snapshot = this.buffer.read(cx).read(cx);
13423            let empty_str: Arc<str> = Arc::default();
13424            let mut suffixes_inserted = Vec::new();
13425            let ignore_indent = action.ignore_indent;
13426
13427            fn comment_prefix_range(
13428                snapshot: &MultiBufferSnapshot,
13429                row: MultiBufferRow,
13430                comment_prefix: &str,
13431                comment_prefix_whitespace: &str,
13432                ignore_indent: bool,
13433            ) -> Range<Point> {
13434                let indent_size = if ignore_indent {
13435                    0
13436                } else {
13437                    snapshot.indent_size_for_line(row).len
13438                };
13439
13440                let start = Point::new(row.0, indent_size);
13441
13442                let mut line_bytes = snapshot
13443                    .bytes_in_range(start..snapshot.max_point())
13444                    .flatten()
13445                    .copied();
13446
13447                // If this line currently begins with the line comment prefix, then record
13448                // the range containing the prefix.
13449                if line_bytes
13450                    .by_ref()
13451                    .take(comment_prefix.len())
13452                    .eq(comment_prefix.bytes())
13453                {
13454                    // Include any whitespace that matches the comment prefix.
13455                    let matching_whitespace_len = line_bytes
13456                        .zip(comment_prefix_whitespace.bytes())
13457                        .take_while(|(a, b)| a == b)
13458                        .count() as u32;
13459                    let end = Point::new(
13460                        start.row,
13461                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13462                    );
13463                    start..end
13464                } else {
13465                    start..start
13466                }
13467            }
13468
13469            fn comment_suffix_range(
13470                snapshot: &MultiBufferSnapshot,
13471                row: MultiBufferRow,
13472                comment_suffix: &str,
13473                comment_suffix_has_leading_space: bool,
13474            ) -> Range<Point> {
13475                let end = Point::new(row.0, snapshot.line_len(row));
13476                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13477
13478                let mut line_end_bytes = snapshot
13479                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13480                    .flatten()
13481                    .copied();
13482
13483                let leading_space_len = if suffix_start_column > 0
13484                    && line_end_bytes.next() == Some(b' ')
13485                    && comment_suffix_has_leading_space
13486                {
13487                    1
13488                } else {
13489                    0
13490                };
13491
13492                // If this line currently begins with the line comment prefix, then record
13493                // the range containing the prefix.
13494                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13495                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13496                    start..end
13497                } else {
13498                    end..end
13499                }
13500            }
13501
13502            // TODO: Handle selections that cross excerpts
13503            for selection in &mut selections {
13504                let start_column = snapshot
13505                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13506                    .len;
13507                let language = if let Some(language) =
13508                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13509                {
13510                    language
13511                } else {
13512                    continue;
13513                };
13514
13515                selection_edit_ranges.clear();
13516
13517                // If multiple selections contain a given row, avoid processing that
13518                // row more than once.
13519                let mut start_row = MultiBufferRow(selection.start.row);
13520                if last_toggled_row == Some(start_row) {
13521                    start_row = start_row.next_row();
13522                }
13523                let end_row =
13524                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13525                        MultiBufferRow(selection.end.row - 1)
13526                    } else {
13527                        MultiBufferRow(selection.end.row)
13528                    };
13529                last_toggled_row = Some(end_row);
13530
13531                if start_row > end_row {
13532                    continue;
13533                }
13534
13535                // If the language has line comments, toggle those.
13536                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13537
13538                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13539                if ignore_indent {
13540                    full_comment_prefixes = full_comment_prefixes
13541                        .into_iter()
13542                        .map(|s| Arc::from(s.trim_end()))
13543                        .collect();
13544                }
13545
13546                if !full_comment_prefixes.is_empty() {
13547                    let first_prefix = full_comment_prefixes
13548                        .first()
13549                        .expect("prefixes is non-empty");
13550                    let prefix_trimmed_lengths = full_comment_prefixes
13551                        .iter()
13552                        .map(|p| p.trim_end_matches(' ').len())
13553                        .collect::<SmallVec<[usize; 4]>>();
13554
13555                    let mut all_selection_lines_are_comments = true;
13556
13557                    for row in start_row.0..=end_row.0 {
13558                        let row = MultiBufferRow(row);
13559                        if start_row < end_row && snapshot.is_line_blank(row) {
13560                            continue;
13561                        }
13562
13563                        let prefix_range = full_comment_prefixes
13564                            .iter()
13565                            .zip(prefix_trimmed_lengths.iter().copied())
13566                            .map(|(prefix, trimmed_prefix_len)| {
13567                                comment_prefix_range(
13568                                    snapshot.deref(),
13569                                    row,
13570                                    &prefix[..trimmed_prefix_len],
13571                                    &prefix[trimmed_prefix_len..],
13572                                    ignore_indent,
13573                                )
13574                            })
13575                            .max_by_key(|range| range.end.column - range.start.column)
13576                            .expect("prefixes is non-empty");
13577
13578                        if prefix_range.is_empty() {
13579                            all_selection_lines_are_comments = false;
13580                        }
13581
13582                        selection_edit_ranges.push(prefix_range);
13583                    }
13584
13585                    if all_selection_lines_are_comments {
13586                        edits.extend(
13587                            selection_edit_ranges
13588                                .iter()
13589                                .cloned()
13590                                .map(|range| (range, empty_str.clone())),
13591                        );
13592                    } else {
13593                        let min_column = selection_edit_ranges
13594                            .iter()
13595                            .map(|range| range.start.column)
13596                            .min()
13597                            .unwrap_or(0);
13598                        edits.extend(selection_edit_ranges.iter().map(|range| {
13599                            let position = Point::new(range.start.row, min_column);
13600                            (position..position, first_prefix.clone())
13601                        }));
13602                    }
13603                } else if let Some((full_comment_prefix, comment_suffix)) =
13604                    language.block_comment_delimiters()
13605                {
13606                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13607                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13608                    let prefix_range = comment_prefix_range(
13609                        snapshot.deref(),
13610                        start_row,
13611                        comment_prefix,
13612                        comment_prefix_whitespace,
13613                        ignore_indent,
13614                    );
13615                    let suffix_range = comment_suffix_range(
13616                        snapshot.deref(),
13617                        end_row,
13618                        comment_suffix.trim_start_matches(' '),
13619                        comment_suffix.starts_with(' '),
13620                    );
13621
13622                    if prefix_range.is_empty() || suffix_range.is_empty() {
13623                        edits.push((
13624                            prefix_range.start..prefix_range.start,
13625                            full_comment_prefix.clone(),
13626                        ));
13627                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13628                        suffixes_inserted.push((end_row, comment_suffix.len()));
13629                    } else {
13630                        edits.push((prefix_range, empty_str.clone()));
13631                        edits.push((suffix_range, empty_str.clone()));
13632                    }
13633                } else {
13634                    continue;
13635                }
13636            }
13637
13638            drop(snapshot);
13639            this.buffer.update(cx, |buffer, cx| {
13640                buffer.edit(edits, None, cx);
13641            });
13642
13643            // Adjust selections so that they end before any comment suffixes that
13644            // were inserted.
13645            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13646            let mut selections = this.selections.all::<Point>(cx);
13647            let snapshot = this.buffer.read(cx).read(cx);
13648            for selection in &mut selections {
13649                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13650                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13651                        Ordering::Less => {
13652                            suffixes_inserted.next();
13653                            continue;
13654                        }
13655                        Ordering::Greater => break,
13656                        Ordering::Equal => {
13657                            if selection.end.column == snapshot.line_len(row) {
13658                                if selection.is_empty() {
13659                                    selection.start.column -= suffix_len as u32;
13660                                }
13661                                selection.end.column -= suffix_len as u32;
13662                            }
13663                            break;
13664                        }
13665                    }
13666                }
13667            }
13668
13669            drop(snapshot);
13670            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13671                s.select(selections)
13672            });
13673
13674            let selections = this.selections.all::<Point>(cx);
13675            let selections_on_single_row = selections.windows(2).all(|selections| {
13676                selections[0].start.row == selections[1].start.row
13677                    && selections[0].end.row == selections[1].end.row
13678                    && selections[0].start.row == selections[0].end.row
13679            });
13680            let selections_selecting = selections
13681                .iter()
13682                .any(|selection| selection.start != selection.end);
13683            let advance_downwards = action.advance_downwards
13684                && selections_on_single_row
13685                && !selections_selecting
13686                && !matches!(this.mode, EditorMode::SingleLine { .. });
13687
13688            if advance_downwards {
13689                let snapshot = this.buffer.read(cx).snapshot(cx);
13690
13691                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13692                    s.move_cursors_with(|display_snapshot, display_point, _| {
13693                        let mut point = display_point.to_point(display_snapshot);
13694                        point.row += 1;
13695                        point = snapshot.clip_point(point, Bias::Left);
13696                        let display_point = point.to_display_point(display_snapshot);
13697                        let goal = SelectionGoal::HorizontalPosition(
13698                            display_snapshot
13699                                .x_for_display_point(display_point, text_layout_details)
13700                                .into(),
13701                        );
13702                        (display_point, goal)
13703                    })
13704                });
13705            }
13706        });
13707    }
13708
13709    pub fn select_enclosing_symbol(
13710        &mut self,
13711        _: &SelectEnclosingSymbol,
13712        window: &mut Window,
13713        cx: &mut Context<Self>,
13714    ) {
13715        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13716
13717        let buffer = self.buffer.read(cx).snapshot(cx);
13718        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13719
13720        fn update_selection(
13721            selection: &Selection<usize>,
13722            buffer_snap: &MultiBufferSnapshot,
13723        ) -> Option<Selection<usize>> {
13724            let cursor = selection.head();
13725            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13726            for symbol in symbols.iter().rev() {
13727                let start = symbol.range.start.to_offset(buffer_snap);
13728                let end = symbol.range.end.to_offset(buffer_snap);
13729                let new_range = start..end;
13730                if start < selection.start || end > selection.end {
13731                    return Some(Selection {
13732                        id: selection.id,
13733                        start: new_range.start,
13734                        end: new_range.end,
13735                        goal: SelectionGoal::None,
13736                        reversed: selection.reversed,
13737                    });
13738                }
13739            }
13740            None
13741        }
13742
13743        let mut selected_larger_symbol = false;
13744        let new_selections = old_selections
13745            .iter()
13746            .map(|selection| match update_selection(selection, &buffer) {
13747                Some(new_selection) => {
13748                    if new_selection.range() != selection.range() {
13749                        selected_larger_symbol = true;
13750                    }
13751                    new_selection
13752                }
13753                None => selection.clone(),
13754            })
13755            .collect::<Vec<_>>();
13756
13757        if selected_larger_symbol {
13758            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13759                s.select(new_selections);
13760            });
13761        }
13762    }
13763
13764    pub fn select_larger_syntax_node(
13765        &mut self,
13766        _: &SelectLargerSyntaxNode,
13767        window: &mut Window,
13768        cx: &mut Context<Self>,
13769    ) {
13770        let Some(visible_row_count) = self.visible_row_count() else {
13771            return;
13772        };
13773        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13774        if old_selections.is_empty() {
13775            return;
13776        }
13777
13778        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13779
13780        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13781        let buffer = self.buffer.read(cx).snapshot(cx);
13782
13783        let mut selected_larger_node = false;
13784        let mut new_selections = old_selections
13785            .iter()
13786            .map(|selection| {
13787                let old_range = selection.start..selection.end;
13788
13789                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13790                    // manually select word at selection
13791                    if ["string_content", "inline"].contains(&node.kind()) {
13792                        let word_range = {
13793                            let display_point = buffer
13794                                .offset_to_point(old_range.start)
13795                                .to_display_point(&display_map);
13796                            let Range { start, end } =
13797                                movement::surrounding_word(&display_map, display_point);
13798                            start.to_point(&display_map).to_offset(&buffer)
13799                                ..end.to_point(&display_map).to_offset(&buffer)
13800                        };
13801                        // ignore if word is already selected
13802                        if !word_range.is_empty() && old_range != word_range {
13803                            let last_word_range = {
13804                                let display_point = buffer
13805                                    .offset_to_point(old_range.end)
13806                                    .to_display_point(&display_map);
13807                                let Range { start, end } =
13808                                    movement::surrounding_word(&display_map, display_point);
13809                                start.to_point(&display_map).to_offset(&buffer)
13810                                    ..end.to_point(&display_map).to_offset(&buffer)
13811                            };
13812                            // only select word if start and end point belongs to same word
13813                            if word_range == last_word_range {
13814                                selected_larger_node = true;
13815                                return Selection {
13816                                    id: selection.id,
13817                                    start: word_range.start,
13818                                    end: word_range.end,
13819                                    goal: SelectionGoal::None,
13820                                    reversed: selection.reversed,
13821                                };
13822                            }
13823                        }
13824                    }
13825                }
13826
13827                let mut new_range = old_range.clone();
13828                while let Some((_node, containing_range)) =
13829                    buffer.syntax_ancestor(new_range.clone())
13830                {
13831                    new_range = match containing_range {
13832                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13833                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13834                    };
13835                    if !display_map.intersects_fold(new_range.start)
13836                        && !display_map.intersects_fold(new_range.end)
13837                    {
13838                        break;
13839                    }
13840                }
13841
13842                selected_larger_node |= new_range != old_range;
13843                Selection {
13844                    id: selection.id,
13845                    start: new_range.start,
13846                    end: new_range.end,
13847                    goal: SelectionGoal::None,
13848                    reversed: selection.reversed,
13849                }
13850            })
13851            .collect::<Vec<_>>();
13852
13853        if !selected_larger_node {
13854            return; // don't put this call in the history
13855        }
13856
13857        // scroll based on transformation done to the last selection created by the user
13858        let (last_old, last_new) = old_selections
13859            .last()
13860            .zip(new_selections.last().cloned())
13861            .expect("old_selections isn't empty");
13862
13863        // revert selection
13864        let is_selection_reversed = {
13865            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13866            new_selections.last_mut().expect("checked above").reversed =
13867                should_newest_selection_be_reversed;
13868            should_newest_selection_be_reversed
13869        };
13870
13871        if selected_larger_node {
13872            self.select_syntax_node_history.disable_clearing = true;
13873            self.change_selections(None, window, cx, |s| {
13874                s.select(new_selections.clone());
13875            });
13876            self.select_syntax_node_history.disable_clearing = false;
13877        }
13878
13879        let start_row = last_new.start.to_display_point(&display_map).row().0;
13880        let end_row = last_new.end.to_display_point(&display_map).row().0;
13881        let selection_height = end_row - start_row + 1;
13882        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13883
13884        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13885        let scroll_behavior = if fits_on_the_screen {
13886            self.request_autoscroll(Autoscroll::fit(), cx);
13887            SelectSyntaxNodeScrollBehavior::FitSelection
13888        } else if is_selection_reversed {
13889            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13890            SelectSyntaxNodeScrollBehavior::CursorTop
13891        } else {
13892            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13893            SelectSyntaxNodeScrollBehavior::CursorBottom
13894        };
13895
13896        self.select_syntax_node_history.push((
13897            old_selections,
13898            scroll_behavior,
13899            is_selection_reversed,
13900        ));
13901    }
13902
13903    pub fn select_smaller_syntax_node(
13904        &mut self,
13905        _: &SelectSmallerSyntaxNode,
13906        window: &mut Window,
13907        cx: &mut Context<Self>,
13908    ) {
13909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13910
13911        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13912            self.select_syntax_node_history.pop()
13913        {
13914            if let Some(selection) = selections.last_mut() {
13915                selection.reversed = is_selection_reversed;
13916            }
13917
13918            self.select_syntax_node_history.disable_clearing = true;
13919            self.change_selections(None, window, cx, |s| {
13920                s.select(selections.to_vec());
13921            });
13922            self.select_syntax_node_history.disable_clearing = false;
13923
13924            match scroll_behavior {
13925                SelectSyntaxNodeScrollBehavior::CursorTop => {
13926                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13927                }
13928                SelectSyntaxNodeScrollBehavior::FitSelection => {
13929                    self.request_autoscroll(Autoscroll::fit(), cx);
13930                }
13931                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13932                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13933                }
13934            }
13935        }
13936    }
13937
13938    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13939        if !EditorSettings::get_global(cx).gutter.runnables {
13940            self.clear_tasks();
13941            return Task::ready(());
13942        }
13943        let project = self.project.as_ref().map(Entity::downgrade);
13944        let task_sources = self.lsp_task_sources(cx);
13945        let multi_buffer = self.buffer.downgrade();
13946        cx.spawn_in(window, async move |editor, cx| {
13947            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13948            let Some(project) = project.and_then(|p| p.upgrade()) else {
13949                return;
13950            };
13951            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13952                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13953            }) else {
13954                return;
13955            };
13956
13957            let hide_runnables = project
13958                .update(cx, |project, cx| {
13959                    // Do not display any test indicators in non-dev server remote projects.
13960                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13961                })
13962                .unwrap_or(true);
13963            if hide_runnables {
13964                return;
13965            }
13966            let new_rows =
13967                cx.background_spawn({
13968                    let snapshot = display_snapshot.clone();
13969                    async move {
13970                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13971                    }
13972                })
13973                    .await;
13974            let Ok(lsp_tasks) =
13975                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13976            else {
13977                return;
13978            };
13979            let lsp_tasks = lsp_tasks.await;
13980
13981            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13982                lsp_tasks
13983                    .into_iter()
13984                    .flat_map(|(kind, tasks)| {
13985                        tasks.into_iter().filter_map(move |(location, task)| {
13986                            Some((kind.clone(), location?, task))
13987                        })
13988                    })
13989                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13990                        let buffer = location.target.buffer;
13991                        let buffer_snapshot = buffer.read(cx).snapshot();
13992                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13993                            |(excerpt_id, snapshot, _)| {
13994                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13995                                    display_snapshot
13996                                        .buffer_snapshot
13997                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13998                                } else {
13999                                    None
14000                                }
14001                            },
14002                        );
14003                        if let Some(offset) = offset {
14004                            let task_buffer_range =
14005                                location.target.range.to_point(&buffer_snapshot);
14006                            let context_buffer_range =
14007                                task_buffer_range.to_offset(&buffer_snapshot);
14008                            let context_range = BufferOffset(context_buffer_range.start)
14009                                ..BufferOffset(context_buffer_range.end);
14010
14011                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14012                                .or_insert_with(|| RunnableTasks {
14013                                    templates: Vec::new(),
14014                                    offset,
14015                                    column: task_buffer_range.start.column,
14016                                    extra_variables: HashMap::default(),
14017                                    context_range,
14018                                })
14019                                .templates
14020                                .push((kind, task.original_task().clone()));
14021                        }
14022
14023                        acc
14024                    })
14025            }) else {
14026                return;
14027            };
14028
14029            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14030                buffer.language_settings(cx).tasks.prefer_lsp
14031            }) else {
14032                return;
14033            };
14034
14035            let rows = Self::runnable_rows(
14036                project,
14037                display_snapshot,
14038                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14039                new_rows,
14040                cx.clone(),
14041            )
14042            .await;
14043            editor
14044                .update(cx, |editor, _| {
14045                    editor.clear_tasks();
14046                    for (key, mut value) in rows {
14047                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14048                            value.templates.extend(lsp_tasks.templates);
14049                        }
14050
14051                        editor.insert_tasks(key, value);
14052                    }
14053                    for (key, value) in lsp_tasks_by_rows {
14054                        editor.insert_tasks(key, value);
14055                    }
14056                })
14057                .ok();
14058        })
14059    }
14060    fn fetch_runnable_ranges(
14061        snapshot: &DisplaySnapshot,
14062        range: Range<Anchor>,
14063    ) -> Vec<language::RunnableRange> {
14064        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14065    }
14066
14067    fn runnable_rows(
14068        project: Entity<Project>,
14069        snapshot: DisplaySnapshot,
14070        prefer_lsp: bool,
14071        runnable_ranges: Vec<RunnableRange>,
14072        cx: AsyncWindowContext,
14073    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14074        cx.spawn(async move |cx| {
14075            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14076            for mut runnable in runnable_ranges {
14077                let Some(tasks) = cx
14078                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14079                    .ok()
14080                else {
14081                    continue;
14082                };
14083                let mut tasks = tasks.await;
14084
14085                if prefer_lsp {
14086                    tasks.retain(|(task_kind, _)| {
14087                        !matches!(task_kind, TaskSourceKind::Language { .. })
14088                    });
14089                }
14090                if tasks.is_empty() {
14091                    continue;
14092                }
14093
14094                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14095                let Some(row) = snapshot
14096                    .buffer_snapshot
14097                    .buffer_line_for_row(MultiBufferRow(point.row))
14098                    .map(|(_, range)| range.start.row)
14099                else {
14100                    continue;
14101                };
14102
14103                let context_range =
14104                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14105                runnable_rows.push((
14106                    (runnable.buffer_id, row),
14107                    RunnableTasks {
14108                        templates: tasks,
14109                        offset: snapshot
14110                            .buffer_snapshot
14111                            .anchor_before(runnable.run_range.start),
14112                        context_range,
14113                        column: point.column,
14114                        extra_variables: runnable.extra_captures,
14115                    },
14116                ));
14117            }
14118            runnable_rows
14119        })
14120    }
14121
14122    fn templates_with_tags(
14123        project: &Entity<Project>,
14124        runnable: &mut Runnable,
14125        cx: &mut App,
14126    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14127        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14128            let (worktree_id, file) = project
14129                .buffer_for_id(runnable.buffer, cx)
14130                .and_then(|buffer| buffer.read(cx).file())
14131                .map(|file| (file.worktree_id(cx), file.clone()))
14132                .unzip();
14133
14134            (
14135                project.task_store().read(cx).task_inventory().cloned(),
14136                worktree_id,
14137                file,
14138            )
14139        });
14140
14141        let tags = mem::take(&mut runnable.tags);
14142        let language = runnable.language.clone();
14143        cx.spawn(async move |cx| {
14144            let mut templates_with_tags = Vec::new();
14145            if let Some(inventory) = inventory {
14146                for RunnableTag(tag) in tags {
14147                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14148                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14149                    }) else {
14150                        return templates_with_tags;
14151                    };
14152                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14153                        move |(_, template)| {
14154                            template.tags.iter().any(|source_tag| source_tag == &tag)
14155                        },
14156                    ));
14157                }
14158            }
14159            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14160
14161            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14162                // Strongest source wins; if we have worktree tag binding, prefer that to
14163                // global and language bindings;
14164                // if we have a global binding, prefer that to language binding.
14165                let first_mismatch = templates_with_tags
14166                    .iter()
14167                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14168                if let Some(index) = first_mismatch {
14169                    templates_with_tags.truncate(index);
14170                }
14171            }
14172
14173            templates_with_tags
14174        })
14175    }
14176
14177    pub fn move_to_enclosing_bracket(
14178        &mut self,
14179        _: &MoveToEnclosingBracket,
14180        window: &mut Window,
14181        cx: &mut Context<Self>,
14182    ) {
14183        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14184        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14185            s.move_offsets_with(|snapshot, selection| {
14186                let Some(enclosing_bracket_ranges) =
14187                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14188                else {
14189                    return;
14190                };
14191
14192                let mut best_length = usize::MAX;
14193                let mut best_inside = false;
14194                let mut best_in_bracket_range = false;
14195                let mut best_destination = None;
14196                for (open, close) in enclosing_bracket_ranges {
14197                    let close = close.to_inclusive();
14198                    let length = close.end() - open.start;
14199                    let inside = selection.start >= open.end && selection.end <= *close.start();
14200                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14201                        || close.contains(&selection.head());
14202
14203                    // If best is next to a bracket and current isn't, skip
14204                    if !in_bracket_range && best_in_bracket_range {
14205                        continue;
14206                    }
14207
14208                    // Prefer smaller lengths unless best is inside and current isn't
14209                    if length > best_length && (best_inside || !inside) {
14210                        continue;
14211                    }
14212
14213                    best_length = length;
14214                    best_inside = inside;
14215                    best_in_bracket_range = in_bracket_range;
14216                    best_destination = Some(
14217                        if close.contains(&selection.start) && close.contains(&selection.end) {
14218                            if inside { open.end } else { open.start }
14219                        } else if inside {
14220                            *close.start()
14221                        } else {
14222                            *close.end()
14223                        },
14224                    );
14225                }
14226
14227                if let Some(destination) = best_destination {
14228                    selection.collapse_to(destination, SelectionGoal::None);
14229                }
14230            })
14231        });
14232    }
14233
14234    pub fn undo_selection(
14235        &mut self,
14236        _: &UndoSelection,
14237        window: &mut Window,
14238        cx: &mut Context<Self>,
14239    ) {
14240        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14241        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14242            self.selection_history.mode = SelectionHistoryMode::Undoing;
14243            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14244                this.end_selection(window, cx);
14245                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14246                    s.select_anchors(entry.selections.to_vec())
14247                });
14248            });
14249            self.selection_history.mode = SelectionHistoryMode::Normal;
14250
14251            self.select_next_state = entry.select_next_state;
14252            self.select_prev_state = entry.select_prev_state;
14253            self.add_selections_state = entry.add_selections_state;
14254        }
14255    }
14256
14257    pub fn redo_selection(
14258        &mut self,
14259        _: &RedoSelection,
14260        window: &mut Window,
14261        cx: &mut Context<Self>,
14262    ) {
14263        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14264        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14265            self.selection_history.mode = SelectionHistoryMode::Redoing;
14266            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14267                this.end_selection(window, cx);
14268                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14269                    s.select_anchors(entry.selections.to_vec())
14270                });
14271            });
14272            self.selection_history.mode = SelectionHistoryMode::Normal;
14273
14274            self.select_next_state = entry.select_next_state;
14275            self.select_prev_state = entry.select_prev_state;
14276            self.add_selections_state = entry.add_selections_state;
14277        }
14278    }
14279
14280    pub fn expand_excerpts(
14281        &mut self,
14282        action: &ExpandExcerpts,
14283        _: &mut Window,
14284        cx: &mut Context<Self>,
14285    ) {
14286        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14287    }
14288
14289    pub fn expand_excerpts_down(
14290        &mut self,
14291        action: &ExpandExcerptsDown,
14292        _: &mut Window,
14293        cx: &mut Context<Self>,
14294    ) {
14295        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14296    }
14297
14298    pub fn expand_excerpts_up(
14299        &mut self,
14300        action: &ExpandExcerptsUp,
14301        _: &mut Window,
14302        cx: &mut Context<Self>,
14303    ) {
14304        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14305    }
14306
14307    pub fn expand_excerpts_for_direction(
14308        &mut self,
14309        lines: u32,
14310        direction: ExpandExcerptDirection,
14311
14312        cx: &mut Context<Self>,
14313    ) {
14314        let selections = self.selections.disjoint_anchors();
14315
14316        let lines = if lines == 0 {
14317            EditorSettings::get_global(cx).expand_excerpt_lines
14318        } else {
14319            lines
14320        };
14321
14322        self.buffer.update(cx, |buffer, cx| {
14323            let snapshot = buffer.snapshot(cx);
14324            let mut excerpt_ids = selections
14325                .iter()
14326                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14327                .collect::<Vec<_>>();
14328            excerpt_ids.sort();
14329            excerpt_ids.dedup();
14330            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14331        })
14332    }
14333
14334    pub fn expand_excerpt(
14335        &mut self,
14336        excerpt: ExcerptId,
14337        direction: ExpandExcerptDirection,
14338        window: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) {
14341        let current_scroll_position = self.scroll_position(cx);
14342        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14343        let mut should_scroll_up = false;
14344
14345        if direction == ExpandExcerptDirection::Down {
14346            let multi_buffer = self.buffer.read(cx);
14347            let snapshot = multi_buffer.snapshot(cx);
14348            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14349                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14350                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14351                        let buffer_snapshot = buffer.read(cx).snapshot();
14352                        let excerpt_end_row =
14353                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14354                        let last_row = buffer_snapshot.max_point().row;
14355                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14356                        should_scroll_up = lines_below >= lines_to_expand;
14357                    }
14358                }
14359            }
14360        }
14361
14362        self.buffer.update(cx, |buffer, cx| {
14363            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14364        });
14365
14366        if should_scroll_up {
14367            let new_scroll_position =
14368                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14369            self.set_scroll_position(new_scroll_position, window, cx);
14370        }
14371    }
14372
14373    pub fn go_to_singleton_buffer_point(
14374        &mut self,
14375        point: Point,
14376        window: &mut Window,
14377        cx: &mut Context<Self>,
14378    ) {
14379        self.go_to_singleton_buffer_range(point..point, window, cx);
14380    }
14381
14382    pub fn go_to_singleton_buffer_range(
14383        &mut self,
14384        range: Range<Point>,
14385        window: &mut Window,
14386        cx: &mut Context<Self>,
14387    ) {
14388        let multibuffer = self.buffer().read(cx);
14389        let Some(buffer) = multibuffer.as_singleton() else {
14390            return;
14391        };
14392        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14393            return;
14394        };
14395        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14396            return;
14397        };
14398        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14399            s.select_anchor_ranges([start..end])
14400        });
14401    }
14402
14403    pub fn go_to_diagnostic(
14404        &mut self,
14405        _: &GoToDiagnostic,
14406        window: &mut Window,
14407        cx: &mut Context<Self>,
14408    ) {
14409        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14410        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14411    }
14412
14413    pub fn go_to_prev_diagnostic(
14414        &mut self,
14415        _: &GoToPreviousDiagnostic,
14416        window: &mut Window,
14417        cx: &mut Context<Self>,
14418    ) {
14419        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14420        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14421    }
14422
14423    pub fn go_to_diagnostic_impl(
14424        &mut self,
14425        direction: Direction,
14426        window: &mut Window,
14427        cx: &mut Context<Self>,
14428    ) {
14429        let buffer = self.buffer.read(cx).snapshot(cx);
14430        let selection = self.selections.newest::<usize>(cx);
14431
14432        let mut active_group_id = None;
14433        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14434            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14435                active_group_id = Some(active_group.group_id);
14436            }
14437        }
14438
14439        fn filtered(
14440            snapshot: EditorSnapshot,
14441            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14442        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14443            diagnostics
14444                .filter(|entry| entry.range.start != entry.range.end)
14445                .filter(|entry| !entry.diagnostic.is_unnecessary)
14446                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14447        }
14448
14449        let snapshot = self.snapshot(window, cx);
14450        let before = filtered(
14451            snapshot.clone(),
14452            buffer
14453                .diagnostics_in_range(0..selection.start)
14454                .filter(|entry| entry.range.start <= selection.start),
14455        );
14456        let after = filtered(
14457            snapshot,
14458            buffer
14459                .diagnostics_in_range(selection.start..buffer.len())
14460                .filter(|entry| entry.range.start >= selection.start),
14461        );
14462
14463        let mut found: Option<DiagnosticEntry<usize>> = None;
14464        if direction == Direction::Prev {
14465            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14466            {
14467                for diagnostic in prev_diagnostics.into_iter().rev() {
14468                    if diagnostic.range.start != selection.start
14469                        || active_group_id
14470                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14471                    {
14472                        found = Some(diagnostic);
14473                        break 'outer;
14474                    }
14475                }
14476            }
14477        } else {
14478            for diagnostic in after.chain(before) {
14479                if diagnostic.range.start != selection.start
14480                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14481                {
14482                    found = Some(diagnostic);
14483                    break;
14484                }
14485            }
14486        }
14487        let Some(next_diagnostic) = found else {
14488            return;
14489        };
14490
14491        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14492            return;
14493        };
14494        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14495            s.select_ranges(vec![
14496                next_diagnostic.range.start..next_diagnostic.range.start,
14497            ])
14498        });
14499        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14500        self.refresh_inline_completion(false, true, window, cx);
14501    }
14502
14503    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14504        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14505        let snapshot = self.snapshot(window, cx);
14506        let selection = self.selections.newest::<Point>(cx);
14507        self.go_to_hunk_before_or_after_position(
14508            &snapshot,
14509            selection.head(),
14510            Direction::Next,
14511            window,
14512            cx,
14513        );
14514    }
14515
14516    pub fn go_to_hunk_before_or_after_position(
14517        &mut self,
14518        snapshot: &EditorSnapshot,
14519        position: Point,
14520        direction: Direction,
14521        window: &mut Window,
14522        cx: &mut Context<Editor>,
14523    ) {
14524        let row = if direction == Direction::Next {
14525            self.hunk_after_position(snapshot, position)
14526                .map(|hunk| hunk.row_range.start)
14527        } else {
14528            self.hunk_before_position(snapshot, position)
14529        };
14530
14531        if let Some(row) = row {
14532            let destination = Point::new(row.0, 0);
14533            let autoscroll = Autoscroll::center();
14534
14535            self.unfold_ranges(&[destination..destination], false, false, cx);
14536            self.change_selections(Some(autoscroll), window, cx, |s| {
14537                s.select_ranges([destination..destination]);
14538            });
14539        }
14540    }
14541
14542    fn hunk_after_position(
14543        &mut self,
14544        snapshot: &EditorSnapshot,
14545        position: Point,
14546    ) -> Option<MultiBufferDiffHunk> {
14547        snapshot
14548            .buffer_snapshot
14549            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14550            .find(|hunk| hunk.row_range.start.0 > position.row)
14551            .or_else(|| {
14552                snapshot
14553                    .buffer_snapshot
14554                    .diff_hunks_in_range(Point::zero()..position)
14555                    .find(|hunk| hunk.row_range.end.0 < position.row)
14556            })
14557    }
14558
14559    fn go_to_prev_hunk(
14560        &mut self,
14561        _: &GoToPreviousHunk,
14562        window: &mut Window,
14563        cx: &mut Context<Self>,
14564    ) {
14565        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14566        let snapshot = self.snapshot(window, cx);
14567        let selection = self.selections.newest::<Point>(cx);
14568        self.go_to_hunk_before_or_after_position(
14569            &snapshot,
14570            selection.head(),
14571            Direction::Prev,
14572            window,
14573            cx,
14574        );
14575    }
14576
14577    fn hunk_before_position(
14578        &mut self,
14579        snapshot: &EditorSnapshot,
14580        position: Point,
14581    ) -> Option<MultiBufferRow> {
14582        snapshot
14583            .buffer_snapshot
14584            .diff_hunk_before(position)
14585            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14586    }
14587
14588    fn go_to_next_change(
14589        &mut self,
14590        _: &GoToNextChange,
14591        window: &mut Window,
14592        cx: &mut Context<Self>,
14593    ) {
14594        if let Some(selections) = self
14595            .change_list
14596            .next_change(1, Direction::Next)
14597            .map(|s| s.to_vec())
14598        {
14599            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14600                let map = s.display_map();
14601                s.select_display_ranges(selections.iter().map(|a| {
14602                    let point = a.to_display_point(&map);
14603                    point..point
14604                }))
14605            })
14606        }
14607    }
14608
14609    fn go_to_previous_change(
14610        &mut self,
14611        _: &GoToPreviousChange,
14612        window: &mut Window,
14613        cx: &mut Context<Self>,
14614    ) {
14615        if let Some(selections) = self
14616            .change_list
14617            .next_change(1, Direction::Prev)
14618            .map(|s| s.to_vec())
14619        {
14620            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14621                let map = s.display_map();
14622                s.select_display_ranges(selections.iter().map(|a| {
14623                    let point = a.to_display_point(&map);
14624                    point..point
14625                }))
14626            })
14627        }
14628    }
14629
14630    fn go_to_line<T: 'static>(
14631        &mut self,
14632        position: Anchor,
14633        highlight_color: Option<Hsla>,
14634        window: &mut Window,
14635        cx: &mut Context<Self>,
14636    ) {
14637        let snapshot = self.snapshot(window, cx).display_snapshot;
14638        let position = position.to_point(&snapshot.buffer_snapshot);
14639        let start = snapshot
14640            .buffer_snapshot
14641            .clip_point(Point::new(position.row, 0), Bias::Left);
14642        let end = start + Point::new(1, 0);
14643        let start = snapshot.buffer_snapshot.anchor_before(start);
14644        let end = snapshot.buffer_snapshot.anchor_before(end);
14645
14646        self.highlight_rows::<T>(
14647            start..end,
14648            highlight_color
14649                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14650            Default::default(),
14651            cx,
14652        );
14653
14654        if self.buffer.read(cx).is_singleton() {
14655            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14656        }
14657    }
14658
14659    pub fn go_to_definition(
14660        &mut self,
14661        _: &GoToDefinition,
14662        window: &mut Window,
14663        cx: &mut Context<Self>,
14664    ) -> Task<Result<Navigated>> {
14665        let definition =
14666            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14667        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14668        cx.spawn_in(window, async move |editor, cx| {
14669            if definition.await? == Navigated::Yes {
14670                return Ok(Navigated::Yes);
14671            }
14672            match fallback_strategy {
14673                GoToDefinitionFallback::None => Ok(Navigated::No),
14674                GoToDefinitionFallback::FindAllReferences => {
14675                    match editor.update_in(cx, |editor, window, cx| {
14676                        editor.find_all_references(&FindAllReferences, window, cx)
14677                    })? {
14678                        Some(references) => references.await,
14679                        None => Ok(Navigated::No),
14680                    }
14681                }
14682            }
14683        })
14684    }
14685
14686    pub fn go_to_declaration(
14687        &mut self,
14688        _: &GoToDeclaration,
14689        window: &mut Window,
14690        cx: &mut Context<Self>,
14691    ) -> Task<Result<Navigated>> {
14692        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14693    }
14694
14695    pub fn go_to_declaration_split(
14696        &mut self,
14697        _: &GoToDeclaration,
14698        window: &mut Window,
14699        cx: &mut Context<Self>,
14700    ) -> Task<Result<Navigated>> {
14701        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14702    }
14703
14704    pub fn go_to_implementation(
14705        &mut self,
14706        _: &GoToImplementation,
14707        window: &mut Window,
14708        cx: &mut Context<Self>,
14709    ) -> Task<Result<Navigated>> {
14710        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14711    }
14712
14713    pub fn go_to_implementation_split(
14714        &mut self,
14715        _: &GoToImplementationSplit,
14716        window: &mut Window,
14717        cx: &mut Context<Self>,
14718    ) -> Task<Result<Navigated>> {
14719        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14720    }
14721
14722    pub fn go_to_type_definition(
14723        &mut self,
14724        _: &GoToTypeDefinition,
14725        window: &mut Window,
14726        cx: &mut Context<Self>,
14727    ) -> Task<Result<Navigated>> {
14728        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14729    }
14730
14731    pub fn go_to_definition_split(
14732        &mut self,
14733        _: &GoToDefinitionSplit,
14734        window: &mut Window,
14735        cx: &mut Context<Self>,
14736    ) -> Task<Result<Navigated>> {
14737        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14738    }
14739
14740    pub fn go_to_type_definition_split(
14741        &mut self,
14742        _: &GoToTypeDefinitionSplit,
14743        window: &mut Window,
14744        cx: &mut Context<Self>,
14745    ) -> Task<Result<Navigated>> {
14746        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14747    }
14748
14749    fn go_to_definition_of_kind(
14750        &mut self,
14751        kind: GotoDefinitionKind,
14752        split: bool,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) -> Task<Result<Navigated>> {
14756        let Some(provider) = self.semantics_provider.clone() else {
14757            return Task::ready(Ok(Navigated::No));
14758        };
14759        let head = self.selections.newest::<usize>(cx).head();
14760        let buffer = self.buffer.read(cx);
14761        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14762            text_anchor
14763        } else {
14764            return Task::ready(Ok(Navigated::No));
14765        };
14766
14767        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14768            return Task::ready(Ok(Navigated::No));
14769        };
14770
14771        cx.spawn_in(window, async move |editor, cx| {
14772            let definitions = definitions.await?;
14773            let navigated = editor
14774                .update_in(cx, |editor, window, cx| {
14775                    editor.navigate_to_hover_links(
14776                        Some(kind),
14777                        definitions
14778                            .into_iter()
14779                            .filter(|location| {
14780                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14781                            })
14782                            .map(HoverLink::Text)
14783                            .collect::<Vec<_>>(),
14784                        split,
14785                        window,
14786                        cx,
14787                    )
14788                })?
14789                .await?;
14790            anyhow::Ok(navigated)
14791        })
14792    }
14793
14794    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14795        let selection = self.selections.newest_anchor();
14796        let head = selection.head();
14797        let tail = selection.tail();
14798
14799        let Some((buffer, start_position)) =
14800            self.buffer.read(cx).text_anchor_for_position(head, cx)
14801        else {
14802            return;
14803        };
14804
14805        let end_position = if head != tail {
14806            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14807                return;
14808            };
14809            Some(pos)
14810        } else {
14811            None
14812        };
14813
14814        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14815            let url = if let Some(end_pos) = end_position {
14816                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14817            } else {
14818                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14819            };
14820
14821            if let Some(url) = url {
14822                editor.update(cx, |_, cx| {
14823                    cx.open_url(&url);
14824                })
14825            } else {
14826                Ok(())
14827            }
14828        });
14829
14830        url_finder.detach();
14831    }
14832
14833    pub fn open_selected_filename(
14834        &mut self,
14835        _: &OpenSelectedFilename,
14836        window: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) {
14839        let Some(workspace) = self.workspace() else {
14840            return;
14841        };
14842
14843        let position = self.selections.newest_anchor().head();
14844
14845        let Some((buffer, buffer_position)) =
14846            self.buffer.read(cx).text_anchor_for_position(position, cx)
14847        else {
14848            return;
14849        };
14850
14851        let project = self.project.clone();
14852
14853        cx.spawn_in(window, async move |_, cx| {
14854            let result = find_file(&buffer, project, buffer_position, cx).await;
14855
14856            if let Some((_, path)) = result {
14857                workspace
14858                    .update_in(cx, |workspace, window, cx| {
14859                        workspace.open_resolved_path(path, window, cx)
14860                    })?
14861                    .await?;
14862            }
14863            anyhow::Ok(())
14864        })
14865        .detach();
14866    }
14867
14868    pub(crate) fn navigate_to_hover_links(
14869        &mut self,
14870        kind: Option<GotoDefinitionKind>,
14871        mut definitions: Vec<HoverLink>,
14872        split: bool,
14873        window: &mut Window,
14874        cx: &mut Context<Editor>,
14875    ) -> Task<Result<Navigated>> {
14876        // If there is one definition, just open it directly
14877        if definitions.len() == 1 {
14878            let definition = definitions.pop().unwrap();
14879
14880            enum TargetTaskResult {
14881                Location(Option<Location>),
14882                AlreadyNavigated,
14883            }
14884
14885            let target_task = match definition {
14886                HoverLink::Text(link) => {
14887                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14888                }
14889                HoverLink::InlayHint(lsp_location, server_id) => {
14890                    let computation =
14891                        self.compute_target_location(lsp_location, server_id, window, cx);
14892                    cx.background_spawn(async move {
14893                        let location = computation.await?;
14894                        Ok(TargetTaskResult::Location(location))
14895                    })
14896                }
14897                HoverLink::Url(url) => {
14898                    cx.open_url(&url);
14899                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14900                }
14901                HoverLink::File(path) => {
14902                    if let Some(workspace) = self.workspace() {
14903                        cx.spawn_in(window, async move |_, cx| {
14904                            workspace
14905                                .update_in(cx, |workspace, window, cx| {
14906                                    workspace.open_resolved_path(path, window, cx)
14907                                })?
14908                                .await
14909                                .map(|_| TargetTaskResult::AlreadyNavigated)
14910                        })
14911                    } else {
14912                        Task::ready(Ok(TargetTaskResult::Location(None)))
14913                    }
14914                }
14915            };
14916            cx.spawn_in(window, async move |editor, cx| {
14917                let target = match target_task.await.context("target resolution task")? {
14918                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14919                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14920                    TargetTaskResult::Location(Some(target)) => target,
14921                };
14922
14923                editor.update_in(cx, |editor, window, cx| {
14924                    let Some(workspace) = editor.workspace() else {
14925                        return Navigated::No;
14926                    };
14927                    let pane = workspace.read(cx).active_pane().clone();
14928
14929                    let range = target.range.to_point(target.buffer.read(cx));
14930                    let range = editor.range_for_match(&range);
14931                    let range = collapse_multiline_range(range);
14932
14933                    if !split
14934                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14935                    {
14936                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14937                    } else {
14938                        window.defer(cx, move |window, cx| {
14939                            let target_editor: Entity<Self> =
14940                                workspace.update(cx, |workspace, cx| {
14941                                    let pane = if split {
14942                                        workspace.adjacent_pane(window, cx)
14943                                    } else {
14944                                        workspace.active_pane().clone()
14945                                    };
14946
14947                                    workspace.open_project_item(
14948                                        pane,
14949                                        target.buffer.clone(),
14950                                        true,
14951                                        true,
14952                                        window,
14953                                        cx,
14954                                    )
14955                                });
14956                            target_editor.update(cx, |target_editor, cx| {
14957                                // When selecting a definition in a different buffer, disable the nav history
14958                                // to avoid creating a history entry at the previous cursor location.
14959                                pane.update(cx, |pane, _| pane.disable_history());
14960                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14961                                pane.update(cx, |pane, _| pane.enable_history());
14962                            });
14963                        });
14964                    }
14965                    Navigated::Yes
14966                })
14967            })
14968        } else if !definitions.is_empty() {
14969            cx.spawn_in(window, async move |editor, cx| {
14970                let (title, location_tasks, workspace) = editor
14971                    .update_in(cx, |editor, window, cx| {
14972                        let tab_kind = match kind {
14973                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14974                            _ => "Definitions",
14975                        };
14976                        let title = definitions
14977                            .iter()
14978                            .find_map(|definition| match definition {
14979                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14980                                    let buffer = origin.buffer.read(cx);
14981                                    format!(
14982                                        "{} for {}",
14983                                        tab_kind,
14984                                        buffer
14985                                            .text_for_range(origin.range.clone())
14986                                            .collect::<String>()
14987                                    )
14988                                }),
14989                                HoverLink::InlayHint(_, _) => None,
14990                                HoverLink::Url(_) => None,
14991                                HoverLink::File(_) => None,
14992                            })
14993                            .unwrap_or(tab_kind.to_string());
14994                        let location_tasks = definitions
14995                            .into_iter()
14996                            .map(|definition| match definition {
14997                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14998                                HoverLink::InlayHint(lsp_location, server_id) => editor
14999                                    .compute_target_location(lsp_location, server_id, window, cx),
15000                                HoverLink::Url(_) => Task::ready(Ok(None)),
15001                                HoverLink::File(_) => Task::ready(Ok(None)),
15002                            })
15003                            .collect::<Vec<_>>();
15004                        (title, location_tasks, editor.workspace().clone())
15005                    })
15006                    .context("location tasks preparation")?;
15007
15008                let locations = future::join_all(location_tasks)
15009                    .await
15010                    .into_iter()
15011                    .filter_map(|location| location.transpose())
15012                    .collect::<Result<_>>()
15013                    .context("location tasks")?;
15014
15015                let Some(workspace) = workspace else {
15016                    return Ok(Navigated::No);
15017                };
15018                let opened = workspace
15019                    .update_in(cx, |workspace, window, cx| {
15020                        Self::open_locations_in_multibuffer(
15021                            workspace,
15022                            locations,
15023                            title,
15024                            split,
15025                            MultibufferSelectionMode::First,
15026                            window,
15027                            cx,
15028                        )
15029                    })
15030                    .ok();
15031
15032                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15033            })
15034        } else {
15035            Task::ready(Ok(Navigated::No))
15036        }
15037    }
15038
15039    fn compute_target_location(
15040        &self,
15041        lsp_location: lsp::Location,
15042        server_id: LanguageServerId,
15043        window: &mut Window,
15044        cx: &mut Context<Self>,
15045    ) -> Task<anyhow::Result<Option<Location>>> {
15046        let Some(project) = self.project.clone() else {
15047            return Task::ready(Ok(None));
15048        };
15049
15050        cx.spawn_in(window, async move |editor, cx| {
15051            let location_task = editor.update(cx, |_, cx| {
15052                project.update(cx, |project, cx| {
15053                    let language_server_name = project
15054                        .language_server_statuses(cx)
15055                        .find(|(id, _)| server_id == *id)
15056                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15057                    language_server_name.map(|language_server_name| {
15058                        project.open_local_buffer_via_lsp(
15059                            lsp_location.uri.clone(),
15060                            server_id,
15061                            language_server_name,
15062                            cx,
15063                        )
15064                    })
15065                })
15066            })?;
15067            let location = match location_task {
15068                Some(task) => Some({
15069                    let target_buffer_handle = task.await.context("open local buffer")?;
15070                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15071                        let target_start = target_buffer
15072                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15073                        let target_end = target_buffer
15074                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15075                        target_buffer.anchor_after(target_start)
15076                            ..target_buffer.anchor_before(target_end)
15077                    })?;
15078                    Location {
15079                        buffer: target_buffer_handle,
15080                        range,
15081                    }
15082                }),
15083                None => None,
15084            };
15085            Ok(location)
15086        })
15087    }
15088
15089    pub fn find_all_references(
15090        &mut self,
15091        _: &FindAllReferences,
15092        window: &mut Window,
15093        cx: &mut Context<Self>,
15094    ) -> Option<Task<Result<Navigated>>> {
15095        let selection = self.selections.newest::<usize>(cx);
15096        let multi_buffer = self.buffer.read(cx);
15097        let head = selection.head();
15098
15099        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15100        let head_anchor = multi_buffer_snapshot.anchor_at(
15101            head,
15102            if head < selection.tail() {
15103                Bias::Right
15104            } else {
15105                Bias::Left
15106            },
15107        );
15108
15109        match self
15110            .find_all_references_task_sources
15111            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15112        {
15113            Ok(_) => {
15114                log::info!(
15115                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15116                );
15117                return None;
15118            }
15119            Err(i) => {
15120                self.find_all_references_task_sources.insert(i, head_anchor);
15121            }
15122        }
15123
15124        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15125        let workspace = self.workspace()?;
15126        let project = workspace.read(cx).project().clone();
15127        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15128        Some(cx.spawn_in(window, async move |editor, cx| {
15129            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15130                if let Ok(i) = editor
15131                    .find_all_references_task_sources
15132                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15133                {
15134                    editor.find_all_references_task_sources.remove(i);
15135                }
15136            });
15137
15138            let locations = references.await?;
15139            if locations.is_empty() {
15140                return anyhow::Ok(Navigated::No);
15141            }
15142
15143            workspace.update_in(cx, |workspace, window, cx| {
15144                let title = locations
15145                    .first()
15146                    .as_ref()
15147                    .map(|location| {
15148                        let buffer = location.buffer.read(cx);
15149                        format!(
15150                            "References to `{}`",
15151                            buffer
15152                                .text_for_range(location.range.clone())
15153                                .collect::<String>()
15154                        )
15155                    })
15156                    .unwrap();
15157                Self::open_locations_in_multibuffer(
15158                    workspace,
15159                    locations,
15160                    title,
15161                    false,
15162                    MultibufferSelectionMode::First,
15163                    window,
15164                    cx,
15165                );
15166                Navigated::Yes
15167            })
15168        }))
15169    }
15170
15171    /// Opens a multibuffer with the given project locations in it
15172    pub fn open_locations_in_multibuffer(
15173        workspace: &mut Workspace,
15174        mut locations: Vec<Location>,
15175        title: String,
15176        split: bool,
15177        multibuffer_selection_mode: MultibufferSelectionMode,
15178        window: &mut Window,
15179        cx: &mut Context<Workspace>,
15180    ) {
15181        // If there are multiple definitions, open them in a multibuffer
15182        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15183        let mut locations = locations.into_iter().peekable();
15184        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15185        let capability = workspace.project().read(cx).capability();
15186
15187        let excerpt_buffer = cx.new(|cx| {
15188            let mut multibuffer = MultiBuffer::new(capability);
15189            while let Some(location) = locations.next() {
15190                let buffer = location.buffer.read(cx);
15191                let mut ranges_for_buffer = Vec::new();
15192                let range = location.range.to_point(buffer);
15193                ranges_for_buffer.push(range.clone());
15194
15195                while let Some(next_location) = locations.peek() {
15196                    if next_location.buffer == location.buffer {
15197                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15198                        locations.next();
15199                    } else {
15200                        break;
15201                    }
15202                }
15203
15204                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15205                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15206                    PathKey::for_buffer(&location.buffer, cx),
15207                    location.buffer.clone(),
15208                    ranges_for_buffer,
15209                    DEFAULT_MULTIBUFFER_CONTEXT,
15210                    cx,
15211                );
15212                ranges.extend(new_ranges)
15213            }
15214
15215            multibuffer.with_title(title)
15216        });
15217
15218        let editor = cx.new(|cx| {
15219            Editor::for_multibuffer(
15220                excerpt_buffer,
15221                Some(workspace.project().clone()),
15222                window,
15223                cx,
15224            )
15225        });
15226        editor.update(cx, |editor, cx| {
15227            match multibuffer_selection_mode {
15228                MultibufferSelectionMode::First => {
15229                    if let Some(first_range) = ranges.first() {
15230                        editor.change_selections(None, window, cx, |selections| {
15231                            selections.clear_disjoint();
15232                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15233                        });
15234                    }
15235                    editor.highlight_background::<Self>(
15236                        &ranges,
15237                        |theme| theme.editor_highlighted_line_background,
15238                        cx,
15239                    );
15240                }
15241                MultibufferSelectionMode::All => {
15242                    editor.change_selections(None, window, cx, |selections| {
15243                        selections.clear_disjoint();
15244                        selections.select_anchor_ranges(ranges);
15245                    });
15246                }
15247            }
15248            editor.register_buffers_with_language_servers(cx);
15249        });
15250
15251        let item = Box::new(editor);
15252        let item_id = item.item_id();
15253
15254        if split {
15255            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15256        } else {
15257            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15258                let (preview_item_id, preview_item_idx) =
15259                    workspace.active_pane().read_with(cx, |pane, _| {
15260                        (pane.preview_item_id(), pane.preview_item_idx())
15261                    });
15262
15263                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15264
15265                if let Some(preview_item_id) = preview_item_id {
15266                    workspace.active_pane().update(cx, |pane, cx| {
15267                        pane.remove_item(preview_item_id, false, false, window, cx);
15268                    });
15269                }
15270            } else {
15271                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15272            }
15273        }
15274        workspace.active_pane().update(cx, |pane, cx| {
15275            pane.set_preview_item_id(Some(item_id), cx);
15276        });
15277    }
15278
15279    pub fn rename(
15280        &mut self,
15281        _: &Rename,
15282        window: &mut Window,
15283        cx: &mut Context<Self>,
15284    ) -> Option<Task<Result<()>>> {
15285        use language::ToOffset as _;
15286
15287        let provider = self.semantics_provider.clone()?;
15288        let selection = self.selections.newest_anchor().clone();
15289        let (cursor_buffer, cursor_buffer_position) = self
15290            .buffer
15291            .read(cx)
15292            .text_anchor_for_position(selection.head(), cx)?;
15293        let (tail_buffer, cursor_buffer_position_end) = self
15294            .buffer
15295            .read(cx)
15296            .text_anchor_for_position(selection.tail(), cx)?;
15297        if tail_buffer != cursor_buffer {
15298            return None;
15299        }
15300
15301        let snapshot = cursor_buffer.read(cx).snapshot();
15302        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15303        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15304        let prepare_rename = provider
15305            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15306            .unwrap_or_else(|| Task::ready(Ok(None)));
15307        drop(snapshot);
15308
15309        Some(cx.spawn_in(window, async move |this, cx| {
15310            let rename_range = if let Some(range) = prepare_rename.await? {
15311                Some(range)
15312            } else {
15313                this.update(cx, |this, cx| {
15314                    let buffer = this.buffer.read(cx).snapshot(cx);
15315                    let mut buffer_highlights = this
15316                        .document_highlights_for_position(selection.head(), &buffer)
15317                        .filter(|highlight| {
15318                            highlight.start.excerpt_id == selection.head().excerpt_id
15319                                && highlight.end.excerpt_id == selection.head().excerpt_id
15320                        });
15321                    buffer_highlights
15322                        .next()
15323                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15324                })?
15325            };
15326            if let Some(rename_range) = rename_range {
15327                this.update_in(cx, |this, window, cx| {
15328                    let snapshot = cursor_buffer.read(cx).snapshot();
15329                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15330                    let cursor_offset_in_rename_range =
15331                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15332                    let cursor_offset_in_rename_range_end =
15333                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15334
15335                    this.take_rename(false, window, cx);
15336                    let buffer = this.buffer.read(cx).read(cx);
15337                    let cursor_offset = selection.head().to_offset(&buffer);
15338                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15339                    let rename_end = rename_start + rename_buffer_range.len();
15340                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15341                    let mut old_highlight_id = None;
15342                    let old_name: Arc<str> = buffer
15343                        .chunks(rename_start..rename_end, true)
15344                        .map(|chunk| {
15345                            if old_highlight_id.is_none() {
15346                                old_highlight_id = chunk.syntax_highlight_id;
15347                            }
15348                            chunk.text
15349                        })
15350                        .collect::<String>()
15351                        .into();
15352
15353                    drop(buffer);
15354
15355                    // Position the selection in the rename editor so that it matches the current selection.
15356                    this.show_local_selections = false;
15357                    let rename_editor = cx.new(|cx| {
15358                        let mut editor = Editor::single_line(window, cx);
15359                        editor.buffer.update(cx, |buffer, cx| {
15360                            buffer.edit([(0..0, old_name.clone())], None, cx)
15361                        });
15362                        let rename_selection_range = match cursor_offset_in_rename_range
15363                            .cmp(&cursor_offset_in_rename_range_end)
15364                        {
15365                            Ordering::Equal => {
15366                                editor.select_all(&SelectAll, window, cx);
15367                                return editor;
15368                            }
15369                            Ordering::Less => {
15370                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15371                            }
15372                            Ordering::Greater => {
15373                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15374                            }
15375                        };
15376                        if rename_selection_range.end > old_name.len() {
15377                            editor.select_all(&SelectAll, window, cx);
15378                        } else {
15379                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15380                                s.select_ranges([rename_selection_range]);
15381                            });
15382                        }
15383                        editor
15384                    });
15385                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15386                        if e == &EditorEvent::Focused {
15387                            cx.emit(EditorEvent::FocusedIn)
15388                        }
15389                    })
15390                    .detach();
15391
15392                    let write_highlights =
15393                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15394                    let read_highlights =
15395                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15396                    let ranges = write_highlights
15397                        .iter()
15398                        .flat_map(|(_, ranges)| ranges.iter())
15399                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15400                        .cloned()
15401                        .collect();
15402
15403                    this.highlight_text::<Rename>(
15404                        ranges,
15405                        HighlightStyle {
15406                            fade_out: Some(0.6),
15407                            ..Default::default()
15408                        },
15409                        cx,
15410                    );
15411                    let rename_focus_handle = rename_editor.focus_handle(cx);
15412                    window.focus(&rename_focus_handle);
15413                    let block_id = this.insert_blocks(
15414                        [BlockProperties {
15415                            style: BlockStyle::Flex,
15416                            placement: BlockPlacement::Below(range.start),
15417                            height: Some(1),
15418                            render: Arc::new({
15419                                let rename_editor = rename_editor.clone();
15420                                move |cx: &mut BlockContext| {
15421                                    let mut text_style = cx.editor_style.text.clone();
15422                                    if let Some(highlight_style) = old_highlight_id
15423                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15424                                    {
15425                                        text_style = text_style.highlight(highlight_style);
15426                                    }
15427                                    div()
15428                                        .block_mouse_except_scroll()
15429                                        .pl(cx.anchor_x)
15430                                        .child(EditorElement::new(
15431                                            &rename_editor,
15432                                            EditorStyle {
15433                                                background: cx.theme().system().transparent,
15434                                                local_player: cx.editor_style.local_player,
15435                                                text: text_style,
15436                                                scrollbar_width: cx.editor_style.scrollbar_width,
15437                                                syntax: cx.editor_style.syntax.clone(),
15438                                                status: cx.editor_style.status.clone(),
15439                                                inlay_hints_style: HighlightStyle {
15440                                                    font_weight: Some(FontWeight::BOLD),
15441                                                    ..make_inlay_hints_style(cx.app)
15442                                                },
15443                                                inline_completion_styles: make_suggestion_styles(
15444                                                    cx.app,
15445                                                ),
15446                                                ..EditorStyle::default()
15447                                            },
15448                                        ))
15449                                        .into_any_element()
15450                                }
15451                            }),
15452                            priority: 0,
15453                            render_in_minimap: true,
15454                        }],
15455                        Some(Autoscroll::fit()),
15456                        cx,
15457                    )[0];
15458                    this.pending_rename = Some(RenameState {
15459                        range,
15460                        old_name,
15461                        editor: rename_editor,
15462                        block_id,
15463                    });
15464                })?;
15465            }
15466
15467            Ok(())
15468        }))
15469    }
15470
15471    pub fn confirm_rename(
15472        &mut self,
15473        _: &ConfirmRename,
15474        window: &mut Window,
15475        cx: &mut Context<Self>,
15476    ) -> Option<Task<Result<()>>> {
15477        let rename = self.take_rename(false, window, cx)?;
15478        let workspace = self.workspace()?.downgrade();
15479        let (buffer, start) = self
15480            .buffer
15481            .read(cx)
15482            .text_anchor_for_position(rename.range.start, cx)?;
15483        let (end_buffer, _) = self
15484            .buffer
15485            .read(cx)
15486            .text_anchor_for_position(rename.range.end, cx)?;
15487        if buffer != end_buffer {
15488            return None;
15489        }
15490
15491        let old_name = rename.old_name;
15492        let new_name = rename.editor.read(cx).text(cx);
15493
15494        let rename = self.semantics_provider.as_ref()?.perform_rename(
15495            &buffer,
15496            start,
15497            new_name.clone(),
15498            cx,
15499        )?;
15500
15501        Some(cx.spawn_in(window, async move |editor, cx| {
15502            let project_transaction = rename.await?;
15503            Self::open_project_transaction(
15504                &editor,
15505                workspace,
15506                project_transaction,
15507                format!("Rename: {}{}", old_name, new_name),
15508                cx,
15509            )
15510            .await?;
15511
15512            editor.update(cx, |editor, cx| {
15513                editor.refresh_document_highlights(cx);
15514            })?;
15515            Ok(())
15516        }))
15517    }
15518
15519    fn take_rename(
15520        &mut self,
15521        moving_cursor: bool,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) -> Option<RenameState> {
15525        let rename = self.pending_rename.take()?;
15526        if rename.editor.focus_handle(cx).is_focused(window) {
15527            window.focus(&self.focus_handle);
15528        }
15529
15530        self.remove_blocks(
15531            [rename.block_id].into_iter().collect(),
15532            Some(Autoscroll::fit()),
15533            cx,
15534        );
15535        self.clear_highlights::<Rename>(cx);
15536        self.show_local_selections = true;
15537
15538        if moving_cursor {
15539            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15540                editor.selections.newest::<usize>(cx).head()
15541            });
15542
15543            // Update the selection to match the position of the selection inside
15544            // the rename editor.
15545            let snapshot = self.buffer.read(cx).read(cx);
15546            let rename_range = rename.range.to_offset(&snapshot);
15547            let cursor_in_editor = snapshot
15548                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15549                .min(rename_range.end);
15550            drop(snapshot);
15551
15552            self.change_selections(None, window, cx, |s| {
15553                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15554            });
15555        } else {
15556            self.refresh_document_highlights(cx);
15557        }
15558
15559        Some(rename)
15560    }
15561
15562    pub fn pending_rename(&self) -> Option<&RenameState> {
15563        self.pending_rename.as_ref()
15564    }
15565
15566    fn format(
15567        &mut self,
15568        _: &Format,
15569        window: &mut Window,
15570        cx: &mut Context<Self>,
15571    ) -> Option<Task<Result<()>>> {
15572        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15573
15574        let project = match &self.project {
15575            Some(project) => project.clone(),
15576            None => return None,
15577        };
15578
15579        Some(self.perform_format(
15580            project,
15581            FormatTrigger::Manual,
15582            FormatTarget::Buffers,
15583            window,
15584            cx,
15585        ))
15586    }
15587
15588    fn format_selections(
15589        &mut self,
15590        _: &FormatSelections,
15591        window: &mut Window,
15592        cx: &mut Context<Self>,
15593    ) -> Option<Task<Result<()>>> {
15594        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15595
15596        let project = match &self.project {
15597            Some(project) => project.clone(),
15598            None => return None,
15599        };
15600
15601        let ranges = self
15602            .selections
15603            .all_adjusted(cx)
15604            .into_iter()
15605            .map(|selection| selection.range())
15606            .collect_vec();
15607
15608        Some(self.perform_format(
15609            project,
15610            FormatTrigger::Manual,
15611            FormatTarget::Ranges(ranges),
15612            window,
15613            cx,
15614        ))
15615    }
15616
15617    fn perform_format(
15618        &mut self,
15619        project: Entity<Project>,
15620        trigger: FormatTrigger,
15621        target: FormatTarget,
15622        window: &mut Window,
15623        cx: &mut Context<Self>,
15624    ) -> Task<Result<()>> {
15625        let buffer = self.buffer.clone();
15626        let (buffers, target) = match target {
15627            FormatTarget::Buffers => {
15628                let mut buffers = buffer.read(cx).all_buffers();
15629                if trigger == FormatTrigger::Save {
15630                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15631                }
15632                (buffers, LspFormatTarget::Buffers)
15633            }
15634            FormatTarget::Ranges(selection_ranges) => {
15635                let multi_buffer = buffer.read(cx);
15636                let snapshot = multi_buffer.read(cx);
15637                let mut buffers = HashSet::default();
15638                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15639                    BTreeMap::new();
15640                for selection_range in selection_ranges {
15641                    for (buffer, buffer_range, _) in
15642                        snapshot.range_to_buffer_ranges(selection_range)
15643                    {
15644                        let buffer_id = buffer.remote_id();
15645                        let start = buffer.anchor_before(buffer_range.start);
15646                        let end = buffer.anchor_after(buffer_range.end);
15647                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15648                        buffer_id_to_ranges
15649                            .entry(buffer_id)
15650                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15651                            .or_insert_with(|| vec![start..end]);
15652                    }
15653                }
15654                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15655            }
15656        };
15657
15658        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15659        let selections_prev = transaction_id_prev
15660            .and_then(|transaction_id_prev| {
15661                // default to selections as they were after the last edit, if we have them,
15662                // instead of how they are now.
15663                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15664                // will take you back to where you made the last edit, instead of staying where you scrolled
15665                self.selection_history
15666                    .transaction(transaction_id_prev)
15667                    .map(|t| t.0.clone())
15668            })
15669            .unwrap_or_else(|| {
15670                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15671                self.selections.disjoint_anchors()
15672            });
15673
15674        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15675        let format = project.update(cx, |project, cx| {
15676            project.format(buffers, target, true, trigger, cx)
15677        });
15678
15679        cx.spawn_in(window, async move |editor, cx| {
15680            let transaction = futures::select_biased! {
15681                transaction = format.log_err().fuse() => transaction,
15682                () = timeout => {
15683                    log::warn!("timed out waiting for formatting");
15684                    None
15685                }
15686            };
15687
15688            buffer
15689                .update(cx, |buffer, cx| {
15690                    if let Some(transaction) = transaction {
15691                        if !buffer.is_singleton() {
15692                            buffer.push_transaction(&transaction.0, cx);
15693                        }
15694                    }
15695                    cx.notify();
15696                })
15697                .ok();
15698
15699            if let Some(transaction_id_now) =
15700                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15701            {
15702                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15703                if has_new_transaction {
15704                    _ = editor.update(cx, |editor, _| {
15705                        editor
15706                            .selection_history
15707                            .insert_transaction(transaction_id_now, selections_prev);
15708                    });
15709                }
15710            }
15711
15712            Ok(())
15713        })
15714    }
15715
15716    fn organize_imports(
15717        &mut self,
15718        _: &OrganizeImports,
15719        window: &mut Window,
15720        cx: &mut Context<Self>,
15721    ) -> Option<Task<Result<()>>> {
15722        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15723        let project = match &self.project {
15724            Some(project) => project.clone(),
15725            None => return None,
15726        };
15727        Some(self.perform_code_action_kind(
15728            project,
15729            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15730            window,
15731            cx,
15732        ))
15733    }
15734
15735    fn perform_code_action_kind(
15736        &mut self,
15737        project: Entity<Project>,
15738        kind: CodeActionKind,
15739        window: &mut Window,
15740        cx: &mut Context<Self>,
15741    ) -> Task<Result<()>> {
15742        let buffer = self.buffer.clone();
15743        let buffers = buffer.read(cx).all_buffers();
15744        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15745        let apply_action = project.update(cx, |project, cx| {
15746            project.apply_code_action_kind(buffers, kind, true, cx)
15747        });
15748        cx.spawn_in(window, async move |_, cx| {
15749            let transaction = futures::select_biased! {
15750                () = timeout => {
15751                    log::warn!("timed out waiting for executing code action");
15752                    None
15753                }
15754                transaction = apply_action.log_err().fuse() => transaction,
15755            };
15756            buffer
15757                .update(cx, |buffer, cx| {
15758                    // check if we need this
15759                    if let Some(transaction) = transaction {
15760                        if !buffer.is_singleton() {
15761                            buffer.push_transaction(&transaction.0, cx);
15762                        }
15763                    }
15764                    cx.notify();
15765                })
15766                .ok();
15767            Ok(())
15768        })
15769    }
15770
15771    fn restart_language_server(
15772        &mut self,
15773        _: &RestartLanguageServer,
15774        _: &mut Window,
15775        cx: &mut Context<Self>,
15776    ) {
15777        if let Some(project) = self.project.clone() {
15778            self.buffer.update(cx, |multi_buffer, cx| {
15779                project.update(cx, |project, cx| {
15780                    project.restart_language_servers_for_buffers(
15781                        multi_buffer.all_buffers().into_iter().collect(),
15782                        cx,
15783                    );
15784                });
15785            })
15786        }
15787    }
15788
15789    fn stop_language_server(
15790        &mut self,
15791        _: &StopLanguageServer,
15792        _: &mut Window,
15793        cx: &mut Context<Self>,
15794    ) {
15795        if let Some(project) = self.project.clone() {
15796            self.buffer.update(cx, |multi_buffer, cx| {
15797                project.update(cx, |project, cx| {
15798                    project.stop_language_servers_for_buffers(
15799                        multi_buffer.all_buffers().into_iter().collect(),
15800                        cx,
15801                    );
15802                    cx.emit(project::Event::RefreshInlayHints);
15803                });
15804            });
15805        }
15806    }
15807
15808    fn cancel_language_server_work(
15809        workspace: &mut Workspace,
15810        _: &actions::CancelLanguageServerWork,
15811        _: &mut Window,
15812        cx: &mut Context<Workspace>,
15813    ) {
15814        let project = workspace.project();
15815        let buffers = workspace
15816            .active_item(cx)
15817            .and_then(|item| item.act_as::<Editor>(cx))
15818            .map_or(HashSet::default(), |editor| {
15819                editor.read(cx).buffer.read(cx).all_buffers()
15820            });
15821        project.update(cx, |project, cx| {
15822            project.cancel_language_server_work_for_buffers(buffers, cx);
15823        });
15824    }
15825
15826    fn show_character_palette(
15827        &mut self,
15828        _: &ShowCharacterPalette,
15829        window: &mut Window,
15830        _: &mut Context<Self>,
15831    ) {
15832        window.show_character_palette();
15833    }
15834
15835    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15836        if self.mode.is_minimap() {
15837            return;
15838        }
15839
15840        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15841            let buffer = self.buffer.read(cx).snapshot(cx);
15842            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15843            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15844            let is_valid = buffer
15845                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15846                .any(|entry| {
15847                    entry.diagnostic.is_primary
15848                        && !entry.range.is_empty()
15849                        && entry.range.start == primary_range_start
15850                        && entry.diagnostic.message == active_diagnostics.active_message
15851                });
15852
15853            if !is_valid {
15854                self.dismiss_diagnostics(cx);
15855            }
15856        }
15857    }
15858
15859    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15860        match &self.active_diagnostics {
15861            ActiveDiagnostic::Group(group) => Some(group),
15862            _ => None,
15863        }
15864    }
15865
15866    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15867        self.dismiss_diagnostics(cx);
15868        self.active_diagnostics = ActiveDiagnostic::All;
15869    }
15870
15871    fn activate_diagnostics(
15872        &mut self,
15873        buffer_id: BufferId,
15874        diagnostic: DiagnosticEntry<usize>,
15875        window: &mut Window,
15876        cx: &mut Context<Self>,
15877    ) {
15878        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15879            return;
15880        }
15881        self.dismiss_diagnostics(cx);
15882        let snapshot = self.snapshot(window, cx);
15883        let buffer = self.buffer.read(cx).snapshot(cx);
15884        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15885            return;
15886        };
15887
15888        let diagnostic_group = buffer
15889            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15890            .collect::<Vec<_>>();
15891
15892        let blocks =
15893            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15894
15895        let blocks = self.display_map.update(cx, |display_map, cx| {
15896            display_map.insert_blocks(blocks, cx).into_iter().collect()
15897        });
15898        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15899            active_range: buffer.anchor_before(diagnostic.range.start)
15900                ..buffer.anchor_after(diagnostic.range.end),
15901            active_message: diagnostic.diagnostic.message.clone(),
15902            group_id: diagnostic.diagnostic.group_id,
15903            blocks,
15904        });
15905        cx.notify();
15906    }
15907
15908    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15909        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15910            return;
15911        };
15912
15913        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15914        if let ActiveDiagnostic::Group(group) = prev {
15915            self.display_map.update(cx, |display_map, cx| {
15916                display_map.remove_blocks(group.blocks, cx);
15917            });
15918            cx.notify();
15919        }
15920    }
15921
15922    /// Disable inline diagnostics rendering for this editor.
15923    pub fn disable_inline_diagnostics(&mut self) {
15924        self.inline_diagnostics_enabled = false;
15925        self.inline_diagnostics_update = Task::ready(());
15926        self.inline_diagnostics.clear();
15927    }
15928
15929    pub fn diagnostics_enabled(&self) -> bool {
15930        self.mode.is_full()
15931    }
15932
15933    pub fn inline_diagnostics_enabled(&self) -> bool {
15934        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15935    }
15936
15937    pub fn show_inline_diagnostics(&self) -> bool {
15938        self.show_inline_diagnostics
15939    }
15940
15941    pub fn toggle_inline_diagnostics(
15942        &mut self,
15943        _: &ToggleInlineDiagnostics,
15944        window: &mut Window,
15945        cx: &mut Context<Editor>,
15946    ) {
15947        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15948        self.refresh_inline_diagnostics(false, window, cx);
15949    }
15950
15951    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15952        self.diagnostics_max_severity = severity;
15953        self.display_map.update(cx, |display_map, _| {
15954            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15955        });
15956    }
15957
15958    pub fn toggle_diagnostics(
15959        &mut self,
15960        _: &ToggleDiagnostics,
15961        window: &mut Window,
15962        cx: &mut Context<Editor>,
15963    ) {
15964        if !self.diagnostics_enabled() {
15965            return;
15966        }
15967
15968        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15969            EditorSettings::get_global(cx)
15970                .diagnostics_max_severity
15971                .filter(|severity| severity != &DiagnosticSeverity::Off)
15972                .unwrap_or(DiagnosticSeverity::Hint)
15973        } else {
15974            DiagnosticSeverity::Off
15975        };
15976        self.set_max_diagnostics_severity(new_severity, cx);
15977        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15978            self.active_diagnostics = ActiveDiagnostic::None;
15979            self.inline_diagnostics_update = Task::ready(());
15980            self.inline_diagnostics.clear();
15981        } else {
15982            self.refresh_inline_diagnostics(false, window, cx);
15983        }
15984
15985        cx.notify();
15986    }
15987
15988    pub fn toggle_minimap(
15989        &mut self,
15990        _: &ToggleMinimap,
15991        window: &mut Window,
15992        cx: &mut Context<Editor>,
15993    ) {
15994        if self.supports_minimap(cx) {
15995            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15996        }
15997    }
15998
15999    fn refresh_inline_diagnostics(
16000        &mut self,
16001        debounce: bool,
16002        window: &mut Window,
16003        cx: &mut Context<Self>,
16004    ) {
16005        let max_severity = ProjectSettings::get_global(cx)
16006            .diagnostics
16007            .inline
16008            .max_severity
16009            .unwrap_or(self.diagnostics_max_severity);
16010
16011        if !self.inline_diagnostics_enabled()
16012            || !self.show_inline_diagnostics
16013            || max_severity == DiagnosticSeverity::Off
16014        {
16015            self.inline_diagnostics_update = Task::ready(());
16016            self.inline_diagnostics.clear();
16017            return;
16018        }
16019
16020        let debounce_ms = ProjectSettings::get_global(cx)
16021            .diagnostics
16022            .inline
16023            .update_debounce_ms;
16024        let debounce = if debounce && debounce_ms > 0 {
16025            Some(Duration::from_millis(debounce_ms))
16026        } else {
16027            None
16028        };
16029        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16030            if let Some(debounce) = debounce {
16031                cx.background_executor().timer(debounce).await;
16032            }
16033            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16034                editor
16035                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16036                    .ok()
16037            }) else {
16038                return;
16039            };
16040
16041            let new_inline_diagnostics = cx
16042                .background_spawn(async move {
16043                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16044                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16045                        let message = diagnostic_entry
16046                            .diagnostic
16047                            .message
16048                            .split_once('\n')
16049                            .map(|(line, _)| line)
16050                            .map(SharedString::new)
16051                            .unwrap_or_else(|| {
16052                                SharedString::from(diagnostic_entry.diagnostic.message)
16053                            });
16054                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16055                        let (Ok(i) | Err(i)) = inline_diagnostics
16056                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16057                        inline_diagnostics.insert(
16058                            i,
16059                            (
16060                                start_anchor,
16061                                InlineDiagnostic {
16062                                    message,
16063                                    group_id: diagnostic_entry.diagnostic.group_id,
16064                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16065                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16066                                    severity: diagnostic_entry.diagnostic.severity,
16067                                },
16068                            ),
16069                        );
16070                    }
16071                    inline_diagnostics
16072                })
16073                .await;
16074
16075            editor
16076                .update(cx, |editor, cx| {
16077                    editor.inline_diagnostics = new_inline_diagnostics;
16078                    cx.notify();
16079                })
16080                .ok();
16081        });
16082    }
16083
16084    fn pull_diagnostics(
16085        &mut self,
16086        buffer_id: Option<BufferId>,
16087        window: &Window,
16088        cx: &mut Context<Self>,
16089    ) -> Option<()> {
16090        if !self.mode().is_full() {
16091            return None;
16092        }
16093        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16094            .diagnostics
16095            .lsp_pull_diagnostics;
16096        if !pull_diagnostics_settings.enabled {
16097            return None;
16098        }
16099        let project = self.project.as_ref()?.downgrade();
16100        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16101        let mut buffers = self.buffer.read(cx).all_buffers();
16102        if let Some(buffer_id) = buffer_id {
16103            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16104        }
16105
16106        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16107            cx.background_executor().timer(debounce).await;
16108
16109            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16110                buffers
16111                    .into_iter()
16112                    .flat_map(|buffer| {
16113                        Some(project.upgrade()?.pull_diagnostics_for_buffer(buffer, cx))
16114                    })
16115                    .collect::<FuturesUnordered<_>>()
16116            }) else {
16117                return;
16118            };
16119
16120            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16121                match pull_task {
16122                    Ok(()) => {
16123                        if editor
16124                            .update_in(cx, |editor, window, cx| {
16125                                editor.update_diagnostics_state(window, cx);
16126                            })
16127                            .is_err()
16128                        {
16129                            return;
16130                        }
16131                    }
16132                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16133                }
16134            }
16135        });
16136
16137        Some(())
16138    }
16139
16140    pub fn set_selections_from_remote(
16141        &mut self,
16142        selections: Vec<Selection<Anchor>>,
16143        pending_selection: Option<Selection<Anchor>>,
16144        window: &mut Window,
16145        cx: &mut Context<Self>,
16146    ) {
16147        let old_cursor_position = self.selections.newest_anchor().head();
16148        self.selections.change_with(cx, |s| {
16149            s.select_anchors(selections);
16150            if let Some(pending_selection) = pending_selection {
16151                s.set_pending(pending_selection, SelectMode::Character);
16152            } else {
16153                s.clear_pending();
16154            }
16155        });
16156        self.selections_did_change(false, &old_cursor_position, true, window, cx);
16157    }
16158
16159    pub fn transact(
16160        &mut self,
16161        window: &mut Window,
16162        cx: &mut Context<Self>,
16163        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16164    ) -> Option<TransactionId> {
16165        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16166            this.start_transaction_at(Instant::now(), window, cx);
16167            update(this, window, cx);
16168            this.end_transaction_at(Instant::now(), cx)
16169        })
16170    }
16171
16172    pub fn start_transaction_at(
16173        &mut self,
16174        now: Instant,
16175        window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) {
16178        self.end_selection(window, cx);
16179        if let Some(tx_id) = self
16180            .buffer
16181            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16182        {
16183            self.selection_history
16184                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16185            cx.emit(EditorEvent::TransactionBegun {
16186                transaction_id: tx_id,
16187            })
16188        }
16189    }
16190
16191    pub fn end_transaction_at(
16192        &mut self,
16193        now: Instant,
16194        cx: &mut Context<Self>,
16195    ) -> Option<TransactionId> {
16196        if let Some(transaction_id) = self
16197            .buffer
16198            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16199        {
16200            if let Some((_, end_selections)) =
16201                self.selection_history.transaction_mut(transaction_id)
16202            {
16203                *end_selections = Some(self.selections.disjoint_anchors());
16204            } else {
16205                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16206            }
16207
16208            cx.emit(EditorEvent::Edited { transaction_id });
16209            Some(transaction_id)
16210        } else {
16211            None
16212        }
16213    }
16214
16215    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16216        if self.selection_mark_mode {
16217            self.change_selections(None, window, cx, |s| {
16218                s.move_with(|_, sel| {
16219                    sel.collapse_to(sel.head(), SelectionGoal::None);
16220                });
16221            })
16222        }
16223        self.selection_mark_mode = true;
16224        cx.notify();
16225    }
16226
16227    pub fn swap_selection_ends(
16228        &mut self,
16229        _: &actions::SwapSelectionEnds,
16230        window: &mut Window,
16231        cx: &mut Context<Self>,
16232    ) {
16233        self.change_selections(None, window, cx, |s| {
16234            s.move_with(|_, sel| {
16235                if sel.start != sel.end {
16236                    sel.reversed = !sel.reversed
16237                }
16238            });
16239        });
16240        self.request_autoscroll(Autoscroll::newest(), cx);
16241        cx.notify();
16242    }
16243
16244    pub fn toggle_fold(
16245        &mut self,
16246        _: &actions::ToggleFold,
16247        window: &mut Window,
16248        cx: &mut Context<Self>,
16249    ) {
16250        if self.is_singleton(cx) {
16251            let selection = self.selections.newest::<Point>(cx);
16252
16253            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16254            let range = if selection.is_empty() {
16255                let point = selection.head().to_display_point(&display_map);
16256                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16257                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16258                    .to_point(&display_map);
16259                start..end
16260            } else {
16261                selection.range()
16262            };
16263            if display_map.folds_in_range(range).next().is_some() {
16264                self.unfold_lines(&Default::default(), window, cx)
16265            } else {
16266                self.fold(&Default::default(), window, cx)
16267            }
16268        } else {
16269            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16270            let buffer_ids: HashSet<_> = self
16271                .selections
16272                .disjoint_anchor_ranges()
16273                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16274                .collect();
16275
16276            let should_unfold = buffer_ids
16277                .iter()
16278                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16279
16280            for buffer_id in buffer_ids {
16281                if should_unfold {
16282                    self.unfold_buffer(buffer_id, cx);
16283                } else {
16284                    self.fold_buffer(buffer_id, cx);
16285                }
16286            }
16287        }
16288    }
16289
16290    pub fn toggle_fold_recursive(
16291        &mut self,
16292        _: &actions::ToggleFoldRecursive,
16293        window: &mut Window,
16294        cx: &mut Context<Self>,
16295    ) {
16296        let selection = self.selections.newest::<Point>(cx);
16297
16298        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16299        let range = if selection.is_empty() {
16300            let point = selection.head().to_display_point(&display_map);
16301            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16302            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16303                .to_point(&display_map);
16304            start..end
16305        } else {
16306            selection.range()
16307        };
16308        if display_map.folds_in_range(range).next().is_some() {
16309            self.unfold_recursive(&Default::default(), window, cx)
16310        } else {
16311            self.fold_recursive(&Default::default(), window, cx)
16312        }
16313    }
16314
16315    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16316        if self.is_singleton(cx) {
16317            let mut to_fold = Vec::new();
16318            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16319            let selections = self.selections.all_adjusted(cx);
16320
16321            for selection in selections {
16322                let range = selection.range().sorted();
16323                let buffer_start_row = range.start.row;
16324
16325                if range.start.row != range.end.row {
16326                    let mut found = false;
16327                    let mut row = range.start.row;
16328                    while row <= range.end.row {
16329                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16330                        {
16331                            found = true;
16332                            row = crease.range().end.row + 1;
16333                            to_fold.push(crease);
16334                        } else {
16335                            row += 1
16336                        }
16337                    }
16338                    if found {
16339                        continue;
16340                    }
16341                }
16342
16343                for row in (0..=range.start.row).rev() {
16344                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16345                        if crease.range().end.row >= buffer_start_row {
16346                            to_fold.push(crease);
16347                            if row <= range.start.row {
16348                                break;
16349                            }
16350                        }
16351                    }
16352                }
16353            }
16354
16355            self.fold_creases(to_fold, true, window, cx);
16356        } else {
16357            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16358            let buffer_ids = self
16359                .selections
16360                .disjoint_anchor_ranges()
16361                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16362                .collect::<HashSet<_>>();
16363            for buffer_id in buffer_ids {
16364                self.fold_buffer(buffer_id, cx);
16365            }
16366        }
16367    }
16368
16369    fn fold_at_level(
16370        &mut self,
16371        fold_at: &FoldAtLevel,
16372        window: &mut Window,
16373        cx: &mut Context<Self>,
16374    ) {
16375        if !self.buffer.read(cx).is_singleton() {
16376            return;
16377        }
16378
16379        let fold_at_level = fold_at.0;
16380        let snapshot = self.buffer.read(cx).snapshot(cx);
16381        let mut to_fold = Vec::new();
16382        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16383
16384        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16385            while start_row < end_row {
16386                match self
16387                    .snapshot(window, cx)
16388                    .crease_for_buffer_row(MultiBufferRow(start_row))
16389                {
16390                    Some(crease) => {
16391                        let nested_start_row = crease.range().start.row + 1;
16392                        let nested_end_row = crease.range().end.row;
16393
16394                        if current_level < fold_at_level {
16395                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16396                        } else if current_level == fold_at_level {
16397                            to_fold.push(crease);
16398                        }
16399
16400                        start_row = nested_end_row + 1;
16401                    }
16402                    None => start_row += 1,
16403                }
16404            }
16405        }
16406
16407        self.fold_creases(to_fold, true, window, cx);
16408    }
16409
16410    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16411        if self.buffer.read(cx).is_singleton() {
16412            let mut fold_ranges = Vec::new();
16413            let snapshot = self.buffer.read(cx).snapshot(cx);
16414
16415            for row in 0..snapshot.max_row().0 {
16416                if let Some(foldable_range) = self
16417                    .snapshot(window, cx)
16418                    .crease_for_buffer_row(MultiBufferRow(row))
16419                {
16420                    fold_ranges.push(foldable_range);
16421                }
16422            }
16423
16424            self.fold_creases(fold_ranges, true, window, cx);
16425        } else {
16426            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16427                editor
16428                    .update_in(cx, |editor, _, cx| {
16429                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16430                            editor.fold_buffer(buffer_id, cx);
16431                        }
16432                    })
16433                    .ok();
16434            });
16435        }
16436    }
16437
16438    pub fn fold_function_bodies(
16439        &mut self,
16440        _: &actions::FoldFunctionBodies,
16441        window: &mut Window,
16442        cx: &mut Context<Self>,
16443    ) {
16444        let snapshot = self.buffer.read(cx).snapshot(cx);
16445
16446        let ranges = snapshot
16447            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16448            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16449            .collect::<Vec<_>>();
16450
16451        let creases = ranges
16452            .into_iter()
16453            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16454            .collect();
16455
16456        self.fold_creases(creases, true, window, cx);
16457    }
16458
16459    pub fn fold_recursive(
16460        &mut self,
16461        _: &actions::FoldRecursive,
16462        window: &mut Window,
16463        cx: &mut Context<Self>,
16464    ) {
16465        let mut to_fold = Vec::new();
16466        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16467        let selections = self.selections.all_adjusted(cx);
16468
16469        for selection in selections {
16470            let range = selection.range().sorted();
16471            let buffer_start_row = range.start.row;
16472
16473            if range.start.row != range.end.row {
16474                let mut found = false;
16475                for row in range.start.row..=range.end.row {
16476                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16477                        found = true;
16478                        to_fold.push(crease);
16479                    }
16480                }
16481                if found {
16482                    continue;
16483                }
16484            }
16485
16486            for row in (0..=range.start.row).rev() {
16487                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16488                    if crease.range().end.row >= buffer_start_row {
16489                        to_fold.push(crease);
16490                    } else {
16491                        break;
16492                    }
16493                }
16494            }
16495        }
16496
16497        self.fold_creases(to_fold, true, window, cx);
16498    }
16499
16500    pub fn fold_at(
16501        &mut self,
16502        buffer_row: MultiBufferRow,
16503        window: &mut Window,
16504        cx: &mut Context<Self>,
16505    ) {
16506        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16507
16508        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16509            let autoscroll = self
16510                .selections
16511                .all::<Point>(cx)
16512                .iter()
16513                .any(|selection| crease.range().overlaps(&selection.range()));
16514
16515            self.fold_creases(vec![crease], autoscroll, window, cx);
16516        }
16517    }
16518
16519    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16520        if self.is_singleton(cx) {
16521            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16522            let buffer = &display_map.buffer_snapshot;
16523            let selections = self.selections.all::<Point>(cx);
16524            let ranges = selections
16525                .iter()
16526                .map(|s| {
16527                    let range = s.display_range(&display_map).sorted();
16528                    let mut start = range.start.to_point(&display_map);
16529                    let mut end = range.end.to_point(&display_map);
16530                    start.column = 0;
16531                    end.column = buffer.line_len(MultiBufferRow(end.row));
16532                    start..end
16533                })
16534                .collect::<Vec<_>>();
16535
16536            self.unfold_ranges(&ranges, true, true, cx);
16537        } else {
16538            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16539            let buffer_ids = self
16540                .selections
16541                .disjoint_anchor_ranges()
16542                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16543                .collect::<HashSet<_>>();
16544            for buffer_id in buffer_ids {
16545                self.unfold_buffer(buffer_id, cx);
16546            }
16547        }
16548    }
16549
16550    pub fn unfold_recursive(
16551        &mut self,
16552        _: &UnfoldRecursive,
16553        _window: &mut Window,
16554        cx: &mut Context<Self>,
16555    ) {
16556        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16557        let selections = self.selections.all::<Point>(cx);
16558        let ranges = selections
16559            .iter()
16560            .map(|s| {
16561                let mut range = s.display_range(&display_map).sorted();
16562                *range.start.column_mut() = 0;
16563                *range.end.column_mut() = display_map.line_len(range.end.row());
16564                let start = range.start.to_point(&display_map);
16565                let end = range.end.to_point(&display_map);
16566                start..end
16567            })
16568            .collect::<Vec<_>>();
16569
16570        self.unfold_ranges(&ranges, true, true, cx);
16571    }
16572
16573    pub fn unfold_at(
16574        &mut self,
16575        buffer_row: MultiBufferRow,
16576        _window: &mut Window,
16577        cx: &mut Context<Self>,
16578    ) {
16579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16580
16581        let intersection_range = Point::new(buffer_row.0, 0)
16582            ..Point::new(
16583                buffer_row.0,
16584                display_map.buffer_snapshot.line_len(buffer_row),
16585            );
16586
16587        let autoscroll = self
16588            .selections
16589            .all::<Point>(cx)
16590            .iter()
16591            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16592
16593        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16594    }
16595
16596    pub fn unfold_all(
16597        &mut self,
16598        _: &actions::UnfoldAll,
16599        _window: &mut Window,
16600        cx: &mut Context<Self>,
16601    ) {
16602        if self.buffer.read(cx).is_singleton() {
16603            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16604            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16605        } else {
16606            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16607                editor
16608                    .update(cx, |editor, cx| {
16609                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16610                            editor.unfold_buffer(buffer_id, cx);
16611                        }
16612                    })
16613                    .ok();
16614            });
16615        }
16616    }
16617
16618    pub fn fold_selected_ranges(
16619        &mut self,
16620        _: &FoldSelectedRanges,
16621        window: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) {
16624        let selections = self.selections.all_adjusted(cx);
16625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16626        let ranges = selections
16627            .into_iter()
16628            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16629            .collect::<Vec<_>>();
16630        self.fold_creases(ranges, true, window, cx);
16631    }
16632
16633    pub fn fold_ranges<T: ToOffset + Clone>(
16634        &mut self,
16635        ranges: Vec<Range<T>>,
16636        auto_scroll: bool,
16637        window: &mut Window,
16638        cx: &mut Context<Self>,
16639    ) {
16640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16641        let ranges = ranges
16642            .into_iter()
16643            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16644            .collect::<Vec<_>>();
16645        self.fold_creases(ranges, auto_scroll, window, cx);
16646    }
16647
16648    pub fn fold_creases<T: ToOffset + Clone>(
16649        &mut self,
16650        creases: Vec<Crease<T>>,
16651        auto_scroll: bool,
16652        _window: &mut Window,
16653        cx: &mut Context<Self>,
16654    ) {
16655        if creases.is_empty() {
16656            return;
16657        }
16658
16659        let mut buffers_affected = HashSet::default();
16660        let multi_buffer = self.buffer().read(cx);
16661        for crease in &creases {
16662            if let Some((_, buffer, _)) =
16663                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16664            {
16665                buffers_affected.insert(buffer.read(cx).remote_id());
16666            };
16667        }
16668
16669        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16670
16671        if auto_scroll {
16672            self.request_autoscroll(Autoscroll::fit(), cx);
16673        }
16674
16675        cx.notify();
16676
16677        self.scrollbar_marker_state.dirty = true;
16678        self.folds_did_change(cx);
16679    }
16680
16681    /// Removes any folds whose ranges intersect any of the given ranges.
16682    pub fn unfold_ranges<T: ToOffset + Clone>(
16683        &mut self,
16684        ranges: &[Range<T>],
16685        inclusive: bool,
16686        auto_scroll: bool,
16687        cx: &mut Context<Self>,
16688    ) {
16689        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16690            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16691        });
16692        self.folds_did_change(cx);
16693    }
16694
16695    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16696        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16697            return;
16698        }
16699        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16700        self.display_map.update(cx, |display_map, cx| {
16701            display_map.fold_buffers([buffer_id], cx)
16702        });
16703        cx.emit(EditorEvent::BufferFoldToggled {
16704            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16705            folded: true,
16706        });
16707        cx.notify();
16708    }
16709
16710    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16711        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16712            return;
16713        }
16714        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16715        self.display_map.update(cx, |display_map, cx| {
16716            display_map.unfold_buffers([buffer_id], cx);
16717        });
16718        cx.emit(EditorEvent::BufferFoldToggled {
16719            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16720            folded: false,
16721        });
16722        cx.notify();
16723    }
16724
16725    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16726        self.display_map.read(cx).is_buffer_folded(buffer)
16727    }
16728
16729    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16730        self.display_map.read(cx).folded_buffers()
16731    }
16732
16733    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16734        self.display_map.update(cx, |display_map, cx| {
16735            display_map.disable_header_for_buffer(buffer_id, cx);
16736        });
16737        cx.notify();
16738    }
16739
16740    /// Removes any folds with the given ranges.
16741    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16742        &mut self,
16743        ranges: &[Range<T>],
16744        type_id: TypeId,
16745        auto_scroll: bool,
16746        cx: &mut Context<Self>,
16747    ) {
16748        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16749            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16750        });
16751        self.folds_did_change(cx);
16752    }
16753
16754    fn remove_folds_with<T: ToOffset + Clone>(
16755        &mut self,
16756        ranges: &[Range<T>],
16757        auto_scroll: bool,
16758        cx: &mut Context<Self>,
16759        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16760    ) {
16761        if ranges.is_empty() {
16762            return;
16763        }
16764
16765        let mut buffers_affected = HashSet::default();
16766        let multi_buffer = self.buffer().read(cx);
16767        for range in ranges {
16768            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16769                buffers_affected.insert(buffer.read(cx).remote_id());
16770            };
16771        }
16772
16773        self.display_map.update(cx, update);
16774
16775        if auto_scroll {
16776            self.request_autoscroll(Autoscroll::fit(), cx);
16777        }
16778
16779        cx.notify();
16780        self.scrollbar_marker_state.dirty = true;
16781        self.active_indent_guides_state.dirty = true;
16782    }
16783
16784    pub fn update_fold_widths(
16785        &mut self,
16786        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16787        cx: &mut Context<Self>,
16788    ) -> bool {
16789        self.display_map
16790            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16791    }
16792
16793    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16794        self.display_map.read(cx).fold_placeholder.clone()
16795    }
16796
16797    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16798        self.buffer.update(cx, |buffer, cx| {
16799            buffer.set_all_diff_hunks_expanded(cx);
16800        });
16801    }
16802
16803    pub fn expand_all_diff_hunks(
16804        &mut self,
16805        _: &ExpandAllDiffHunks,
16806        _window: &mut Window,
16807        cx: &mut Context<Self>,
16808    ) {
16809        self.buffer.update(cx, |buffer, cx| {
16810            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16811        });
16812    }
16813
16814    pub fn toggle_selected_diff_hunks(
16815        &mut self,
16816        _: &ToggleSelectedDiffHunks,
16817        _window: &mut Window,
16818        cx: &mut Context<Self>,
16819    ) {
16820        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16821        self.toggle_diff_hunks_in_ranges(ranges, cx);
16822    }
16823
16824    pub fn diff_hunks_in_ranges<'a>(
16825        &'a self,
16826        ranges: &'a [Range<Anchor>],
16827        buffer: &'a MultiBufferSnapshot,
16828    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16829        ranges.iter().flat_map(move |range| {
16830            let end_excerpt_id = range.end.excerpt_id;
16831            let range = range.to_point(buffer);
16832            let mut peek_end = range.end;
16833            if range.end.row < buffer.max_row().0 {
16834                peek_end = Point::new(range.end.row + 1, 0);
16835            }
16836            buffer
16837                .diff_hunks_in_range(range.start..peek_end)
16838                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16839        })
16840    }
16841
16842    pub fn has_stageable_diff_hunks_in_ranges(
16843        &self,
16844        ranges: &[Range<Anchor>],
16845        snapshot: &MultiBufferSnapshot,
16846    ) -> bool {
16847        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16848        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16849    }
16850
16851    pub fn toggle_staged_selected_diff_hunks(
16852        &mut self,
16853        _: &::git::ToggleStaged,
16854        _: &mut Window,
16855        cx: &mut Context<Self>,
16856    ) {
16857        let snapshot = self.buffer.read(cx).snapshot(cx);
16858        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16859        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16860        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16861    }
16862
16863    pub fn set_render_diff_hunk_controls(
16864        &mut self,
16865        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16866        cx: &mut Context<Self>,
16867    ) {
16868        self.render_diff_hunk_controls = render_diff_hunk_controls;
16869        cx.notify();
16870    }
16871
16872    pub fn stage_and_next(
16873        &mut self,
16874        _: &::git::StageAndNext,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        self.do_stage_or_unstage_and_next(true, window, cx);
16879    }
16880
16881    pub fn unstage_and_next(
16882        &mut self,
16883        _: &::git::UnstageAndNext,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) {
16887        self.do_stage_or_unstage_and_next(false, window, cx);
16888    }
16889
16890    pub fn stage_or_unstage_diff_hunks(
16891        &mut self,
16892        stage: bool,
16893        ranges: Vec<Range<Anchor>>,
16894        cx: &mut Context<Self>,
16895    ) {
16896        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16897        cx.spawn(async move |this, cx| {
16898            task.await?;
16899            this.update(cx, |this, cx| {
16900                let snapshot = this.buffer.read(cx).snapshot(cx);
16901                let chunk_by = this
16902                    .diff_hunks_in_ranges(&ranges, &snapshot)
16903                    .chunk_by(|hunk| hunk.buffer_id);
16904                for (buffer_id, hunks) in &chunk_by {
16905                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16906                }
16907            })
16908        })
16909        .detach_and_log_err(cx);
16910    }
16911
16912    fn save_buffers_for_ranges_if_needed(
16913        &mut self,
16914        ranges: &[Range<Anchor>],
16915        cx: &mut Context<Editor>,
16916    ) -> Task<Result<()>> {
16917        let multibuffer = self.buffer.read(cx);
16918        let snapshot = multibuffer.read(cx);
16919        let buffer_ids: HashSet<_> = ranges
16920            .iter()
16921            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16922            .collect();
16923        drop(snapshot);
16924
16925        let mut buffers = HashSet::default();
16926        for buffer_id in buffer_ids {
16927            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16928                let buffer = buffer_entity.read(cx);
16929                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16930                {
16931                    buffers.insert(buffer_entity);
16932                }
16933            }
16934        }
16935
16936        if let Some(project) = &self.project {
16937            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16938        } else {
16939            Task::ready(Ok(()))
16940        }
16941    }
16942
16943    fn do_stage_or_unstage_and_next(
16944        &mut self,
16945        stage: bool,
16946        window: &mut Window,
16947        cx: &mut Context<Self>,
16948    ) {
16949        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16950
16951        if ranges.iter().any(|range| range.start != range.end) {
16952            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16953            return;
16954        }
16955
16956        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16957        let snapshot = self.snapshot(window, cx);
16958        let position = self.selections.newest::<Point>(cx).head();
16959        let mut row = snapshot
16960            .buffer_snapshot
16961            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16962            .find(|hunk| hunk.row_range.start.0 > position.row)
16963            .map(|hunk| hunk.row_range.start);
16964
16965        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16966        // Outside of the project diff editor, wrap around to the beginning.
16967        if !all_diff_hunks_expanded {
16968            row = row.or_else(|| {
16969                snapshot
16970                    .buffer_snapshot
16971                    .diff_hunks_in_range(Point::zero()..position)
16972                    .find(|hunk| hunk.row_range.end.0 < position.row)
16973                    .map(|hunk| hunk.row_range.start)
16974            });
16975        }
16976
16977        if let Some(row) = row {
16978            let destination = Point::new(row.0, 0);
16979            let autoscroll = Autoscroll::center();
16980
16981            self.unfold_ranges(&[destination..destination], false, false, cx);
16982            self.change_selections(Some(autoscroll), window, cx, |s| {
16983                s.select_ranges([destination..destination]);
16984            });
16985        }
16986    }
16987
16988    fn do_stage_or_unstage(
16989        &self,
16990        stage: bool,
16991        buffer_id: BufferId,
16992        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16993        cx: &mut App,
16994    ) -> Option<()> {
16995        let project = self.project.as_ref()?;
16996        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16997        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16998        let buffer_snapshot = buffer.read(cx).snapshot();
16999        let file_exists = buffer_snapshot
17000            .file()
17001            .is_some_and(|file| file.disk_state().exists());
17002        diff.update(cx, |diff, cx| {
17003            diff.stage_or_unstage_hunks(
17004                stage,
17005                &hunks
17006                    .map(|hunk| buffer_diff::DiffHunk {
17007                        buffer_range: hunk.buffer_range,
17008                        diff_base_byte_range: hunk.diff_base_byte_range,
17009                        secondary_status: hunk.secondary_status,
17010                        range: Point::zero()..Point::zero(), // unused
17011                    })
17012                    .collect::<Vec<_>>(),
17013                &buffer_snapshot,
17014                file_exists,
17015                cx,
17016            )
17017        });
17018        None
17019    }
17020
17021    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17022        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17023        self.buffer
17024            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17025    }
17026
17027    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17028        self.buffer.update(cx, |buffer, cx| {
17029            let ranges = vec![Anchor::min()..Anchor::max()];
17030            if !buffer.all_diff_hunks_expanded()
17031                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17032            {
17033                buffer.collapse_diff_hunks(ranges, cx);
17034                true
17035            } else {
17036                false
17037            }
17038        })
17039    }
17040
17041    fn toggle_diff_hunks_in_ranges(
17042        &mut self,
17043        ranges: Vec<Range<Anchor>>,
17044        cx: &mut Context<Editor>,
17045    ) {
17046        self.buffer.update(cx, |buffer, cx| {
17047            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17048            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17049        })
17050    }
17051
17052    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17053        self.buffer.update(cx, |buffer, cx| {
17054            let snapshot = buffer.snapshot(cx);
17055            let excerpt_id = range.end.excerpt_id;
17056            let point_range = range.to_point(&snapshot);
17057            let expand = !buffer.single_hunk_is_expanded(range, cx);
17058            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17059        })
17060    }
17061
17062    pub(crate) fn apply_all_diff_hunks(
17063        &mut self,
17064        _: &ApplyAllDiffHunks,
17065        window: &mut Window,
17066        cx: &mut Context<Self>,
17067    ) {
17068        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17069
17070        let buffers = self.buffer.read(cx).all_buffers();
17071        for branch_buffer in buffers {
17072            branch_buffer.update(cx, |branch_buffer, cx| {
17073                branch_buffer.merge_into_base(Vec::new(), cx);
17074            });
17075        }
17076
17077        if let Some(project) = self.project.clone() {
17078            self.save(true, project, window, cx).detach_and_log_err(cx);
17079        }
17080    }
17081
17082    pub(crate) fn apply_selected_diff_hunks(
17083        &mut self,
17084        _: &ApplyDiffHunk,
17085        window: &mut Window,
17086        cx: &mut Context<Self>,
17087    ) {
17088        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17089        let snapshot = self.snapshot(window, cx);
17090        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17091        let mut ranges_by_buffer = HashMap::default();
17092        self.transact(window, cx, |editor, _window, cx| {
17093            for hunk in hunks {
17094                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17095                    ranges_by_buffer
17096                        .entry(buffer.clone())
17097                        .or_insert_with(Vec::new)
17098                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17099                }
17100            }
17101
17102            for (buffer, ranges) in ranges_by_buffer {
17103                buffer.update(cx, |buffer, cx| {
17104                    buffer.merge_into_base(ranges, cx);
17105                });
17106            }
17107        });
17108
17109        if let Some(project) = self.project.clone() {
17110            self.save(true, project, window, cx).detach_and_log_err(cx);
17111        }
17112    }
17113
17114    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17115        if hovered != self.gutter_hovered {
17116            self.gutter_hovered = hovered;
17117            cx.notify();
17118        }
17119    }
17120
17121    pub fn insert_blocks(
17122        &mut self,
17123        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17124        autoscroll: Option<Autoscroll>,
17125        cx: &mut Context<Self>,
17126    ) -> Vec<CustomBlockId> {
17127        let blocks = self
17128            .display_map
17129            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17130        if let Some(autoscroll) = autoscroll {
17131            self.request_autoscroll(autoscroll, cx);
17132        }
17133        cx.notify();
17134        blocks
17135    }
17136
17137    pub fn resize_blocks(
17138        &mut self,
17139        heights: HashMap<CustomBlockId, u32>,
17140        autoscroll: Option<Autoscroll>,
17141        cx: &mut Context<Self>,
17142    ) {
17143        self.display_map
17144            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17145        if let Some(autoscroll) = autoscroll {
17146            self.request_autoscroll(autoscroll, cx);
17147        }
17148        cx.notify();
17149    }
17150
17151    pub fn replace_blocks(
17152        &mut self,
17153        renderers: HashMap<CustomBlockId, RenderBlock>,
17154        autoscroll: Option<Autoscroll>,
17155        cx: &mut Context<Self>,
17156    ) {
17157        self.display_map
17158            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17159        if let Some(autoscroll) = autoscroll {
17160            self.request_autoscroll(autoscroll, cx);
17161        }
17162        cx.notify();
17163    }
17164
17165    pub fn remove_blocks(
17166        &mut self,
17167        block_ids: HashSet<CustomBlockId>,
17168        autoscroll: Option<Autoscroll>,
17169        cx: &mut Context<Self>,
17170    ) {
17171        self.display_map.update(cx, |display_map, cx| {
17172            display_map.remove_blocks(block_ids, cx)
17173        });
17174        if let Some(autoscroll) = autoscroll {
17175            self.request_autoscroll(autoscroll, cx);
17176        }
17177        cx.notify();
17178    }
17179
17180    pub fn row_for_block(
17181        &self,
17182        block_id: CustomBlockId,
17183        cx: &mut Context<Self>,
17184    ) -> Option<DisplayRow> {
17185        self.display_map
17186            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17187    }
17188
17189    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17190        self.focused_block = Some(focused_block);
17191    }
17192
17193    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17194        self.focused_block.take()
17195    }
17196
17197    pub fn insert_creases(
17198        &mut self,
17199        creases: impl IntoIterator<Item = Crease<Anchor>>,
17200        cx: &mut Context<Self>,
17201    ) -> Vec<CreaseId> {
17202        self.display_map
17203            .update(cx, |map, cx| map.insert_creases(creases, cx))
17204    }
17205
17206    pub fn remove_creases(
17207        &mut self,
17208        ids: impl IntoIterator<Item = CreaseId>,
17209        cx: &mut Context<Self>,
17210    ) -> Vec<(CreaseId, Range<Anchor>)> {
17211        self.display_map
17212            .update(cx, |map, cx| map.remove_creases(ids, cx))
17213    }
17214
17215    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17216        self.display_map
17217            .update(cx, |map, cx| map.snapshot(cx))
17218            .longest_row()
17219    }
17220
17221    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17222        self.display_map
17223            .update(cx, |map, cx| map.snapshot(cx))
17224            .max_point()
17225    }
17226
17227    pub fn text(&self, cx: &App) -> String {
17228        self.buffer.read(cx).read(cx).text()
17229    }
17230
17231    pub fn is_empty(&self, cx: &App) -> bool {
17232        self.buffer.read(cx).read(cx).is_empty()
17233    }
17234
17235    pub fn text_option(&self, cx: &App) -> Option<String> {
17236        let text = self.text(cx);
17237        let text = text.trim();
17238
17239        if text.is_empty() {
17240            return None;
17241        }
17242
17243        Some(text.to_string())
17244    }
17245
17246    pub fn set_text(
17247        &mut self,
17248        text: impl Into<Arc<str>>,
17249        window: &mut Window,
17250        cx: &mut Context<Self>,
17251    ) {
17252        self.transact(window, cx, |this, _, cx| {
17253            this.buffer
17254                .read(cx)
17255                .as_singleton()
17256                .expect("you can only call set_text on editors for singleton buffers")
17257                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17258        });
17259    }
17260
17261    pub fn display_text(&self, cx: &mut App) -> String {
17262        self.display_map
17263            .update(cx, |map, cx| map.snapshot(cx))
17264            .text()
17265    }
17266
17267    fn create_minimap(
17268        &self,
17269        minimap_settings: MinimapSettings,
17270        window: &mut Window,
17271        cx: &mut Context<Self>,
17272    ) -> Option<Entity<Self>> {
17273        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17274            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17275    }
17276
17277    fn initialize_new_minimap(
17278        &self,
17279        minimap_settings: MinimapSettings,
17280        window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) -> Entity<Self> {
17283        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17284
17285        let mut minimap = Editor::new_internal(
17286            EditorMode::Minimap {
17287                parent: cx.weak_entity(),
17288            },
17289            self.buffer.clone(),
17290            self.project.clone(),
17291            Some(self.display_map.clone()),
17292            window,
17293            cx,
17294        );
17295        minimap.scroll_manager.clone_state(&self.scroll_manager);
17296        minimap.set_text_style_refinement(TextStyleRefinement {
17297            font_size: Some(MINIMAP_FONT_SIZE),
17298            font_weight: Some(MINIMAP_FONT_WEIGHT),
17299            ..Default::default()
17300        });
17301        minimap.update_minimap_configuration(minimap_settings, cx);
17302        cx.new(|_| minimap)
17303    }
17304
17305    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17306        let current_line_highlight = minimap_settings
17307            .current_line_highlight
17308            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17309        self.set_current_line_highlight(Some(current_line_highlight));
17310    }
17311
17312    pub fn minimap(&self) -> Option<&Entity<Self>> {
17313        self.minimap
17314            .as_ref()
17315            .filter(|_| self.minimap_visibility.visible())
17316    }
17317
17318    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17319        let mut wrap_guides = smallvec![];
17320
17321        if self.show_wrap_guides == Some(false) {
17322            return wrap_guides;
17323        }
17324
17325        let settings = self.buffer.read(cx).language_settings(cx);
17326        if settings.show_wrap_guides {
17327            match self.soft_wrap_mode(cx) {
17328                SoftWrap::Column(soft_wrap) => {
17329                    wrap_guides.push((soft_wrap as usize, true));
17330                }
17331                SoftWrap::Bounded(soft_wrap) => {
17332                    wrap_guides.push((soft_wrap as usize, true));
17333                }
17334                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17335            }
17336            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17337        }
17338
17339        wrap_guides
17340    }
17341
17342    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17343        let settings = self.buffer.read(cx).language_settings(cx);
17344        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17345        match mode {
17346            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17347                SoftWrap::None
17348            }
17349            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17350            language_settings::SoftWrap::PreferredLineLength => {
17351                SoftWrap::Column(settings.preferred_line_length)
17352            }
17353            language_settings::SoftWrap::Bounded => {
17354                SoftWrap::Bounded(settings.preferred_line_length)
17355            }
17356        }
17357    }
17358
17359    pub fn set_soft_wrap_mode(
17360        &mut self,
17361        mode: language_settings::SoftWrap,
17362
17363        cx: &mut Context<Self>,
17364    ) {
17365        self.soft_wrap_mode_override = Some(mode);
17366        cx.notify();
17367    }
17368
17369    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17370        self.hard_wrap = hard_wrap;
17371        cx.notify();
17372    }
17373
17374    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17375        self.text_style_refinement = Some(style);
17376    }
17377
17378    /// called by the Element so we know what style we were most recently rendered with.
17379    pub(crate) fn set_style(
17380        &mut self,
17381        style: EditorStyle,
17382        window: &mut Window,
17383        cx: &mut Context<Self>,
17384    ) {
17385        // We intentionally do not inform the display map about the minimap style
17386        // so that wrapping is not recalculated and stays consistent for the editor
17387        // and its linked minimap.
17388        if !self.mode.is_minimap() {
17389            let rem_size = window.rem_size();
17390            self.display_map.update(cx, |map, cx| {
17391                map.set_font(
17392                    style.text.font(),
17393                    style.text.font_size.to_pixels(rem_size),
17394                    cx,
17395                )
17396            });
17397        }
17398        self.style = Some(style);
17399    }
17400
17401    pub fn style(&self) -> Option<&EditorStyle> {
17402        self.style.as_ref()
17403    }
17404
17405    // Called by the element. This method is not designed to be called outside of the editor
17406    // element's layout code because it does not notify when rewrapping is computed synchronously.
17407    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17408        self.display_map
17409            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17410    }
17411
17412    pub fn set_soft_wrap(&mut self) {
17413        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17414    }
17415
17416    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17417        if self.soft_wrap_mode_override.is_some() {
17418            self.soft_wrap_mode_override.take();
17419        } else {
17420            let soft_wrap = match self.soft_wrap_mode(cx) {
17421                SoftWrap::GitDiff => return,
17422                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17423                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17424                    language_settings::SoftWrap::None
17425                }
17426            };
17427            self.soft_wrap_mode_override = Some(soft_wrap);
17428        }
17429        cx.notify();
17430    }
17431
17432    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17433        let Some(workspace) = self.workspace() else {
17434            return;
17435        };
17436        let fs = workspace.read(cx).app_state().fs.clone();
17437        let current_show = TabBarSettings::get_global(cx).show;
17438        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17439            setting.show = Some(!current_show);
17440        });
17441    }
17442
17443    pub fn toggle_indent_guides(
17444        &mut self,
17445        _: &ToggleIndentGuides,
17446        _: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) {
17449        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17450            self.buffer
17451                .read(cx)
17452                .language_settings(cx)
17453                .indent_guides
17454                .enabled
17455        });
17456        self.show_indent_guides = Some(!currently_enabled);
17457        cx.notify();
17458    }
17459
17460    fn should_show_indent_guides(&self) -> Option<bool> {
17461        self.show_indent_guides
17462    }
17463
17464    pub fn toggle_line_numbers(
17465        &mut self,
17466        _: &ToggleLineNumbers,
17467        _: &mut Window,
17468        cx: &mut Context<Self>,
17469    ) {
17470        let mut editor_settings = EditorSettings::get_global(cx).clone();
17471        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17472        EditorSettings::override_global(editor_settings, cx);
17473    }
17474
17475    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17476        if let Some(show_line_numbers) = self.show_line_numbers {
17477            return show_line_numbers;
17478        }
17479        EditorSettings::get_global(cx).gutter.line_numbers
17480    }
17481
17482    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17483        self.use_relative_line_numbers
17484            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17485    }
17486
17487    pub fn toggle_relative_line_numbers(
17488        &mut self,
17489        _: &ToggleRelativeLineNumbers,
17490        _: &mut Window,
17491        cx: &mut Context<Self>,
17492    ) {
17493        let is_relative = self.should_use_relative_line_numbers(cx);
17494        self.set_relative_line_number(Some(!is_relative), cx)
17495    }
17496
17497    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17498        self.use_relative_line_numbers = is_relative;
17499        cx.notify();
17500    }
17501
17502    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17503        self.show_gutter = show_gutter;
17504        cx.notify();
17505    }
17506
17507    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17508        self.show_scrollbars = ScrollbarAxes {
17509            horizontal: show,
17510            vertical: show,
17511        };
17512        cx.notify();
17513    }
17514
17515    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17516        self.show_scrollbars.vertical = show;
17517        cx.notify();
17518    }
17519
17520    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17521        self.show_scrollbars.horizontal = show;
17522        cx.notify();
17523    }
17524
17525    pub fn set_minimap_visibility(
17526        &mut self,
17527        minimap_visibility: MinimapVisibility,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        if self.minimap_visibility != minimap_visibility {
17532            if minimap_visibility.visible() && self.minimap.is_none() {
17533                let minimap_settings = EditorSettings::get_global(cx).minimap;
17534                self.minimap =
17535                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17536            }
17537            self.minimap_visibility = minimap_visibility;
17538            cx.notify();
17539        }
17540    }
17541
17542    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17543        self.set_show_scrollbars(false, cx);
17544        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17545    }
17546
17547    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17548        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17549    }
17550
17551    /// Normally the text in full mode and auto height editors is padded on the
17552    /// left side by roughly half a character width for improved hit testing.
17553    ///
17554    /// Use this method to disable this for cases where this is not wanted (e.g.
17555    /// if you want to align the editor text with some other text above or below)
17556    /// or if you want to add this padding to single-line editors.
17557    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17558        self.offset_content = offset_content;
17559        cx.notify();
17560    }
17561
17562    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17563        self.show_line_numbers = Some(show_line_numbers);
17564        cx.notify();
17565    }
17566
17567    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17568        self.disable_expand_excerpt_buttons = true;
17569        cx.notify();
17570    }
17571
17572    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17573        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17574        cx.notify();
17575    }
17576
17577    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17578        self.show_code_actions = Some(show_code_actions);
17579        cx.notify();
17580    }
17581
17582    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17583        self.show_runnables = Some(show_runnables);
17584        cx.notify();
17585    }
17586
17587    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17588        self.show_breakpoints = Some(show_breakpoints);
17589        cx.notify();
17590    }
17591
17592    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17593        if self.display_map.read(cx).masked != masked {
17594            self.display_map.update(cx, |map, _| map.masked = masked);
17595        }
17596        cx.notify()
17597    }
17598
17599    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17600        self.show_wrap_guides = Some(show_wrap_guides);
17601        cx.notify();
17602    }
17603
17604    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17605        self.show_indent_guides = Some(show_indent_guides);
17606        cx.notify();
17607    }
17608
17609    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17610        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17611            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17612                if let Some(dir) = file.abs_path(cx).parent() {
17613                    return Some(dir.to_owned());
17614                }
17615            }
17616
17617            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17618                return Some(project_path.path.to_path_buf());
17619            }
17620        }
17621
17622        None
17623    }
17624
17625    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17626        self.active_excerpt(cx)?
17627            .1
17628            .read(cx)
17629            .file()
17630            .and_then(|f| f.as_local())
17631    }
17632
17633    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17634        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17635            let buffer = buffer.read(cx);
17636            if let Some(project_path) = buffer.project_path(cx) {
17637                let project = self.project.as_ref()?.read(cx);
17638                project.absolute_path(&project_path, cx)
17639            } else {
17640                buffer
17641                    .file()
17642                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17643            }
17644        })
17645    }
17646
17647    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17648        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17649            let project_path = buffer.read(cx).project_path(cx)?;
17650            let project = self.project.as_ref()?.read(cx);
17651            let entry = project.entry_for_path(&project_path, cx)?;
17652            let path = entry.path.to_path_buf();
17653            Some(path)
17654        })
17655    }
17656
17657    pub fn reveal_in_finder(
17658        &mut self,
17659        _: &RevealInFileManager,
17660        _window: &mut Window,
17661        cx: &mut Context<Self>,
17662    ) {
17663        if let Some(target) = self.target_file(cx) {
17664            cx.reveal_path(&target.abs_path(cx));
17665        }
17666    }
17667
17668    pub fn copy_path(
17669        &mut self,
17670        _: &zed_actions::workspace::CopyPath,
17671        _window: &mut Window,
17672        cx: &mut Context<Self>,
17673    ) {
17674        if let Some(path) = self.target_file_abs_path(cx) {
17675            if let Some(path) = path.to_str() {
17676                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17677            }
17678        }
17679    }
17680
17681    pub fn copy_relative_path(
17682        &mut self,
17683        _: &zed_actions::workspace::CopyRelativePath,
17684        _window: &mut Window,
17685        cx: &mut Context<Self>,
17686    ) {
17687        if let Some(path) = self.target_file_path(cx) {
17688            if let Some(path) = path.to_str() {
17689                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17690            }
17691        }
17692    }
17693
17694    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17695        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17696            buffer.read(cx).project_path(cx)
17697        } else {
17698            None
17699        }
17700    }
17701
17702    // Returns true if the editor handled a go-to-line request
17703    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17704        maybe!({
17705            let breakpoint_store = self.breakpoint_store.as_ref()?;
17706
17707            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17708            else {
17709                self.clear_row_highlights::<ActiveDebugLine>();
17710                return None;
17711            };
17712
17713            let position = active_stack_frame.position;
17714            let buffer_id = position.buffer_id?;
17715            let snapshot = self
17716                .project
17717                .as_ref()?
17718                .read(cx)
17719                .buffer_for_id(buffer_id, cx)?
17720                .read(cx)
17721                .snapshot();
17722
17723            let mut handled = false;
17724            for (id, ExcerptRange { context, .. }) in
17725                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17726            {
17727                if context.start.cmp(&position, &snapshot).is_ge()
17728                    || context.end.cmp(&position, &snapshot).is_lt()
17729                {
17730                    continue;
17731                }
17732                let snapshot = self.buffer.read(cx).snapshot(cx);
17733                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17734
17735                handled = true;
17736                self.clear_row_highlights::<ActiveDebugLine>();
17737
17738                self.go_to_line::<ActiveDebugLine>(
17739                    multibuffer_anchor,
17740                    Some(cx.theme().colors().editor_debugger_active_line_background),
17741                    window,
17742                    cx,
17743                );
17744
17745                cx.notify();
17746            }
17747
17748            handled.then_some(())
17749        })
17750        .is_some()
17751    }
17752
17753    pub fn copy_file_name_without_extension(
17754        &mut self,
17755        _: &CopyFileNameWithoutExtension,
17756        _: &mut Window,
17757        cx: &mut Context<Self>,
17758    ) {
17759        if let Some(file) = self.target_file(cx) {
17760            if let Some(file_stem) = file.path().file_stem() {
17761                if let Some(name) = file_stem.to_str() {
17762                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17763                }
17764            }
17765        }
17766    }
17767
17768    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17769        if let Some(file) = self.target_file(cx) {
17770            if let Some(file_name) = file.path().file_name() {
17771                if let Some(name) = file_name.to_str() {
17772                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17773                }
17774            }
17775        }
17776    }
17777
17778    pub fn toggle_git_blame(
17779        &mut self,
17780        _: &::git::Blame,
17781        window: &mut Window,
17782        cx: &mut Context<Self>,
17783    ) {
17784        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17785
17786        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17787            self.start_git_blame(true, window, cx);
17788        }
17789
17790        cx.notify();
17791    }
17792
17793    pub fn toggle_git_blame_inline(
17794        &mut self,
17795        _: &ToggleGitBlameInline,
17796        window: &mut Window,
17797        cx: &mut Context<Self>,
17798    ) {
17799        self.toggle_git_blame_inline_internal(true, window, cx);
17800        cx.notify();
17801    }
17802
17803    pub fn open_git_blame_commit(
17804        &mut self,
17805        _: &OpenGitBlameCommit,
17806        window: &mut Window,
17807        cx: &mut Context<Self>,
17808    ) {
17809        self.open_git_blame_commit_internal(window, cx);
17810    }
17811
17812    fn open_git_blame_commit_internal(
17813        &mut self,
17814        window: &mut Window,
17815        cx: &mut Context<Self>,
17816    ) -> Option<()> {
17817        let blame = self.blame.as_ref()?;
17818        let snapshot = self.snapshot(window, cx);
17819        let cursor = self.selections.newest::<Point>(cx).head();
17820        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17821        let blame_entry = blame
17822            .update(cx, |blame, cx| {
17823                blame
17824                    .blame_for_rows(
17825                        &[RowInfo {
17826                            buffer_id: Some(buffer.remote_id()),
17827                            buffer_row: Some(point.row),
17828                            ..Default::default()
17829                        }],
17830                        cx,
17831                    )
17832                    .next()
17833            })
17834            .flatten()?;
17835        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17836        let repo = blame.read(cx).repository(cx)?;
17837        let workspace = self.workspace()?.downgrade();
17838        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17839        None
17840    }
17841
17842    pub fn git_blame_inline_enabled(&self) -> bool {
17843        self.git_blame_inline_enabled
17844    }
17845
17846    pub fn toggle_selection_menu(
17847        &mut self,
17848        _: &ToggleSelectionMenu,
17849        _: &mut Window,
17850        cx: &mut Context<Self>,
17851    ) {
17852        self.show_selection_menu = self
17853            .show_selection_menu
17854            .map(|show_selections_menu| !show_selections_menu)
17855            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17856
17857        cx.notify();
17858    }
17859
17860    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17861        self.show_selection_menu
17862            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17863    }
17864
17865    fn start_git_blame(
17866        &mut self,
17867        user_triggered: bool,
17868        window: &mut Window,
17869        cx: &mut Context<Self>,
17870    ) {
17871        if let Some(project) = self.project.as_ref() {
17872            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17873                return;
17874            };
17875
17876            if buffer.read(cx).file().is_none() {
17877                return;
17878            }
17879
17880            let focused = self.focus_handle(cx).contains_focused(window, cx);
17881
17882            let project = project.clone();
17883            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17884            self.blame_subscription =
17885                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17886            self.blame = Some(blame);
17887        }
17888    }
17889
17890    fn toggle_git_blame_inline_internal(
17891        &mut self,
17892        user_triggered: bool,
17893        window: &mut Window,
17894        cx: &mut Context<Self>,
17895    ) {
17896        if self.git_blame_inline_enabled {
17897            self.git_blame_inline_enabled = false;
17898            self.show_git_blame_inline = false;
17899            self.show_git_blame_inline_delay_task.take();
17900        } else {
17901            self.git_blame_inline_enabled = true;
17902            self.start_git_blame_inline(user_triggered, window, cx);
17903        }
17904
17905        cx.notify();
17906    }
17907
17908    fn start_git_blame_inline(
17909        &mut self,
17910        user_triggered: bool,
17911        window: &mut Window,
17912        cx: &mut Context<Self>,
17913    ) {
17914        self.start_git_blame(user_triggered, window, cx);
17915
17916        if ProjectSettings::get_global(cx)
17917            .git
17918            .inline_blame_delay()
17919            .is_some()
17920        {
17921            self.start_inline_blame_timer(window, cx);
17922        } else {
17923            self.show_git_blame_inline = true
17924        }
17925    }
17926
17927    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17928        self.blame.as_ref()
17929    }
17930
17931    pub fn show_git_blame_gutter(&self) -> bool {
17932        self.show_git_blame_gutter
17933    }
17934
17935    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17936        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17937    }
17938
17939    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17940        self.show_git_blame_inline
17941            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17942            && !self.newest_selection_head_on_empty_line(cx)
17943            && self.has_blame_entries(cx)
17944    }
17945
17946    fn has_blame_entries(&self, cx: &App) -> bool {
17947        self.blame()
17948            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17949    }
17950
17951    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17952        let cursor_anchor = self.selections.newest_anchor().head();
17953
17954        let snapshot = self.buffer.read(cx).snapshot(cx);
17955        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17956
17957        snapshot.line_len(buffer_row) == 0
17958    }
17959
17960    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17961        let buffer_and_selection = maybe!({
17962            let selection = self.selections.newest::<Point>(cx);
17963            let selection_range = selection.range();
17964
17965            let multi_buffer = self.buffer().read(cx);
17966            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17967            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17968
17969            let (buffer, range, _) = if selection.reversed {
17970                buffer_ranges.first()
17971            } else {
17972                buffer_ranges.last()
17973            }?;
17974
17975            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17976                ..text::ToPoint::to_point(&range.end, &buffer).row;
17977            Some((
17978                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17979                selection,
17980            ))
17981        });
17982
17983        let Some((buffer, selection)) = buffer_and_selection else {
17984            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17985        };
17986
17987        let Some(project) = self.project.as_ref() else {
17988            return Task::ready(Err(anyhow!("editor does not have project")));
17989        };
17990
17991        project.update(cx, |project, cx| {
17992            project.get_permalink_to_line(&buffer, selection, cx)
17993        })
17994    }
17995
17996    pub fn copy_permalink_to_line(
17997        &mut self,
17998        _: &CopyPermalinkToLine,
17999        window: &mut Window,
18000        cx: &mut Context<Self>,
18001    ) {
18002        let permalink_task = self.get_permalink_to_line(cx);
18003        let workspace = self.workspace();
18004
18005        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18006            Ok(permalink) => {
18007                cx.update(|_, cx| {
18008                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18009                })
18010                .ok();
18011            }
18012            Err(err) => {
18013                let message = format!("Failed to copy permalink: {err}");
18014
18015                anyhow::Result::<()>::Err(err).log_err();
18016
18017                if let Some(workspace) = workspace {
18018                    workspace
18019                        .update_in(cx, |workspace, _, cx| {
18020                            struct CopyPermalinkToLine;
18021
18022                            workspace.show_toast(
18023                                Toast::new(
18024                                    NotificationId::unique::<CopyPermalinkToLine>(),
18025                                    message,
18026                                ),
18027                                cx,
18028                            )
18029                        })
18030                        .ok();
18031                }
18032            }
18033        })
18034        .detach();
18035    }
18036
18037    pub fn copy_file_location(
18038        &mut self,
18039        _: &CopyFileLocation,
18040        _: &mut Window,
18041        cx: &mut Context<Self>,
18042    ) {
18043        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18044        if let Some(file) = self.target_file(cx) {
18045            if let Some(path) = file.path().to_str() {
18046                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18047            }
18048        }
18049    }
18050
18051    pub fn open_permalink_to_line(
18052        &mut self,
18053        _: &OpenPermalinkToLine,
18054        window: &mut Window,
18055        cx: &mut Context<Self>,
18056    ) {
18057        let permalink_task = self.get_permalink_to_line(cx);
18058        let workspace = self.workspace();
18059
18060        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18061            Ok(permalink) => {
18062                cx.update(|_, cx| {
18063                    cx.open_url(permalink.as_ref());
18064                })
18065                .ok();
18066            }
18067            Err(err) => {
18068                let message = format!("Failed to open permalink: {err}");
18069
18070                anyhow::Result::<()>::Err(err).log_err();
18071
18072                if let Some(workspace) = workspace {
18073                    workspace
18074                        .update(cx, |workspace, cx| {
18075                            struct OpenPermalinkToLine;
18076
18077                            workspace.show_toast(
18078                                Toast::new(
18079                                    NotificationId::unique::<OpenPermalinkToLine>(),
18080                                    message,
18081                                ),
18082                                cx,
18083                            )
18084                        })
18085                        .ok();
18086                }
18087            }
18088        })
18089        .detach();
18090    }
18091
18092    pub fn insert_uuid_v4(
18093        &mut self,
18094        _: &InsertUuidV4,
18095        window: &mut Window,
18096        cx: &mut Context<Self>,
18097    ) {
18098        self.insert_uuid(UuidVersion::V4, window, cx);
18099    }
18100
18101    pub fn insert_uuid_v7(
18102        &mut self,
18103        _: &InsertUuidV7,
18104        window: &mut Window,
18105        cx: &mut Context<Self>,
18106    ) {
18107        self.insert_uuid(UuidVersion::V7, window, cx);
18108    }
18109
18110    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18111        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
18112        self.transact(window, cx, |this, window, cx| {
18113            let edits = this
18114                .selections
18115                .all::<Point>(cx)
18116                .into_iter()
18117                .map(|selection| {
18118                    let uuid = match version {
18119                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18120                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18121                    };
18122
18123                    (selection.range(), uuid.to_string())
18124                });
18125            this.edit(edits, cx);
18126            this.refresh_inline_completion(true, false, window, cx);
18127        });
18128    }
18129
18130    pub fn open_selections_in_multibuffer(
18131        &mut self,
18132        _: &OpenSelectionsInMultibuffer,
18133        window: &mut Window,
18134        cx: &mut Context<Self>,
18135    ) {
18136        let multibuffer = self.buffer.read(cx);
18137
18138        let Some(buffer) = multibuffer.as_singleton() else {
18139            return;
18140        };
18141
18142        let Some(workspace) = self.workspace() else {
18143            return;
18144        };
18145
18146        let locations = self
18147            .selections
18148            .disjoint_anchors()
18149            .iter()
18150            .map(|range| Location {
18151                buffer: buffer.clone(),
18152                range: range.start.text_anchor..range.end.text_anchor,
18153            })
18154            .collect::<Vec<_>>();
18155
18156        let title = multibuffer.title(cx).to_string();
18157
18158        cx.spawn_in(window, async move |_, cx| {
18159            workspace.update_in(cx, |workspace, window, cx| {
18160                Self::open_locations_in_multibuffer(
18161                    workspace,
18162                    locations,
18163                    format!("Selections for '{title}'"),
18164                    false,
18165                    MultibufferSelectionMode::All,
18166                    window,
18167                    cx,
18168                );
18169            })
18170        })
18171        .detach();
18172    }
18173
18174    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18175    /// last highlight added will be used.
18176    ///
18177    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18178    pub fn highlight_rows<T: 'static>(
18179        &mut self,
18180        range: Range<Anchor>,
18181        color: Hsla,
18182        options: RowHighlightOptions,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let snapshot = self.buffer().read(cx).snapshot(cx);
18186        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18187        let ix = row_highlights.binary_search_by(|highlight| {
18188            Ordering::Equal
18189                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18190                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18191        });
18192
18193        if let Err(mut ix) = ix {
18194            let index = post_inc(&mut self.highlight_order);
18195
18196            // If this range intersects with the preceding highlight, then merge it with
18197            // the preceding highlight. Otherwise insert a new highlight.
18198            let mut merged = false;
18199            if ix > 0 {
18200                let prev_highlight = &mut row_highlights[ix - 1];
18201                if prev_highlight
18202                    .range
18203                    .end
18204                    .cmp(&range.start, &snapshot)
18205                    .is_ge()
18206                {
18207                    ix -= 1;
18208                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18209                        prev_highlight.range.end = range.end;
18210                    }
18211                    merged = true;
18212                    prev_highlight.index = index;
18213                    prev_highlight.color = color;
18214                    prev_highlight.options = options;
18215                }
18216            }
18217
18218            if !merged {
18219                row_highlights.insert(
18220                    ix,
18221                    RowHighlight {
18222                        range: range.clone(),
18223                        index,
18224                        color,
18225                        options,
18226                        type_id: TypeId::of::<T>(),
18227                    },
18228                );
18229            }
18230
18231            // If any of the following highlights intersect with this one, merge them.
18232            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18233                let highlight = &row_highlights[ix];
18234                if next_highlight
18235                    .range
18236                    .start
18237                    .cmp(&highlight.range.end, &snapshot)
18238                    .is_le()
18239                {
18240                    if next_highlight
18241                        .range
18242                        .end
18243                        .cmp(&highlight.range.end, &snapshot)
18244                        .is_gt()
18245                    {
18246                        row_highlights[ix].range.end = next_highlight.range.end;
18247                    }
18248                    row_highlights.remove(ix + 1);
18249                } else {
18250                    break;
18251                }
18252            }
18253        }
18254    }
18255
18256    /// Remove any highlighted row ranges of the given type that intersect the
18257    /// given ranges.
18258    pub fn remove_highlighted_rows<T: 'static>(
18259        &mut self,
18260        ranges_to_remove: Vec<Range<Anchor>>,
18261        cx: &mut Context<Self>,
18262    ) {
18263        let snapshot = self.buffer().read(cx).snapshot(cx);
18264        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18265        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18266        row_highlights.retain(|highlight| {
18267            while let Some(range_to_remove) = ranges_to_remove.peek() {
18268                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18269                    Ordering::Less | Ordering::Equal => {
18270                        ranges_to_remove.next();
18271                    }
18272                    Ordering::Greater => {
18273                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18274                            Ordering::Less | Ordering::Equal => {
18275                                return false;
18276                            }
18277                            Ordering::Greater => break,
18278                        }
18279                    }
18280                }
18281            }
18282
18283            true
18284        })
18285    }
18286
18287    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18288    pub fn clear_row_highlights<T: 'static>(&mut self) {
18289        self.highlighted_rows.remove(&TypeId::of::<T>());
18290    }
18291
18292    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18293    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18294        self.highlighted_rows
18295            .get(&TypeId::of::<T>())
18296            .map_or(&[] as &[_], |vec| vec.as_slice())
18297            .iter()
18298            .map(|highlight| (highlight.range.clone(), highlight.color))
18299    }
18300
18301    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18302    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18303    /// Allows to ignore certain kinds of highlights.
18304    pub fn highlighted_display_rows(
18305        &self,
18306        window: &mut Window,
18307        cx: &mut App,
18308    ) -> BTreeMap<DisplayRow, LineHighlight> {
18309        let snapshot = self.snapshot(window, cx);
18310        let mut used_highlight_orders = HashMap::default();
18311        self.highlighted_rows
18312            .iter()
18313            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18314            .fold(
18315                BTreeMap::<DisplayRow, LineHighlight>::new(),
18316                |mut unique_rows, highlight| {
18317                    let start = highlight.range.start.to_display_point(&snapshot);
18318                    let end = highlight.range.end.to_display_point(&snapshot);
18319                    let start_row = start.row().0;
18320                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18321                        && end.column() == 0
18322                    {
18323                        end.row().0.saturating_sub(1)
18324                    } else {
18325                        end.row().0
18326                    };
18327                    for row in start_row..=end_row {
18328                        let used_index =
18329                            used_highlight_orders.entry(row).or_insert(highlight.index);
18330                        if highlight.index >= *used_index {
18331                            *used_index = highlight.index;
18332                            unique_rows.insert(
18333                                DisplayRow(row),
18334                                LineHighlight {
18335                                    include_gutter: highlight.options.include_gutter,
18336                                    border: None,
18337                                    background: highlight.color.into(),
18338                                    type_id: Some(highlight.type_id),
18339                                },
18340                            );
18341                        }
18342                    }
18343                    unique_rows
18344                },
18345            )
18346    }
18347
18348    pub fn highlighted_display_row_for_autoscroll(
18349        &self,
18350        snapshot: &DisplaySnapshot,
18351    ) -> Option<DisplayRow> {
18352        self.highlighted_rows
18353            .values()
18354            .flat_map(|highlighted_rows| highlighted_rows.iter())
18355            .filter_map(|highlight| {
18356                if highlight.options.autoscroll {
18357                    Some(highlight.range.start.to_display_point(snapshot).row())
18358                } else {
18359                    None
18360                }
18361            })
18362            .min()
18363    }
18364
18365    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18366        self.highlight_background::<SearchWithinRange>(
18367            ranges,
18368            |colors| colors.editor_document_highlight_read_background,
18369            cx,
18370        )
18371    }
18372
18373    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18374        self.breadcrumb_header = Some(new_header);
18375    }
18376
18377    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18378        self.clear_background_highlights::<SearchWithinRange>(cx);
18379    }
18380
18381    pub fn highlight_background<T: 'static>(
18382        &mut self,
18383        ranges: &[Range<Anchor>],
18384        color_fetcher: fn(&ThemeColors) -> Hsla,
18385        cx: &mut Context<Self>,
18386    ) {
18387        self.background_highlights
18388            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18389        self.scrollbar_marker_state.dirty = true;
18390        cx.notify();
18391    }
18392
18393    pub fn clear_background_highlights<T: 'static>(
18394        &mut self,
18395        cx: &mut Context<Self>,
18396    ) -> Option<BackgroundHighlight> {
18397        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18398        if !text_highlights.1.is_empty() {
18399            self.scrollbar_marker_state.dirty = true;
18400            cx.notify();
18401        }
18402        Some(text_highlights)
18403    }
18404
18405    pub fn highlight_gutter<T: 'static>(
18406        &mut self,
18407        ranges: impl Into<Vec<Range<Anchor>>>,
18408        color_fetcher: fn(&App) -> Hsla,
18409        cx: &mut Context<Self>,
18410    ) {
18411        self.gutter_highlights
18412            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18413        cx.notify();
18414    }
18415
18416    pub fn clear_gutter_highlights<T: 'static>(
18417        &mut self,
18418        cx: &mut Context<Self>,
18419    ) -> Option<GutterHighlight> {
18420        cx.notify();
18421        self.gutter_highlights.remove(&TypeId::of::<T>())
18422    }
18423
18424    pub fn insert_gutter_highlight<T: 'static>(
18425        &mut self,
18426        range: Range<Anchor>,
18427        color_fetcher: fn(&App) -> Hsla,
18428        cx: &mut Context<Self>,
18429    ) {
18430        let snapshot = self.buffer().read(cx).snapshot(cx);
18431        let mut highlights = self
18432            .gutter_highlights
18433            .remove(&TypeId::of::<T>())
18434            .map(|(_, highlights)| highlights)
18435            .unwrap_or_default();
18436        let ix = highlights.binary_search_by(|highlight| {
18437            Ordering::Equal
18438                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18439                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18440        });
18441        if let Err(ix) = ix {
18442            highlights.insert(ix, range);
18443        }
18444        self.gutter_highlights
18445            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18446    }
18447
18448    pub fn remove_gutter_highlights<T: 'static>(
18449        &mut self,
18450        ranges_to_remove: Vec<Range<Anchor>>,
18451        cx: &mut Context<Self>,
18452    ) {
18453        let snapshot = self.buffer().read(cx).snapshot(cx);
18454        let Some((color_fetcher, mut gutter_highlights)) =
18455            self.gutter_highlights.remove(&TypeId::of::<T>())
18456        else {
18457            return;
18458        };
18459        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18460        gutter_highlights.retain(|highlight| {
18461            while let Some(range_to_remove) = ranges_to_remove.peek() {
18462                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18463                    Ordering::Less | Ordering::Equal => {
18464                        ranges_to_remove.next();
18465                    }
18466                    Ordering::Greater => {
18467                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18468                            Ordering::Less | Ordering::Equal => {
18469                                return false;
18470                            }
18471                            Ordering::Greater => break,
18472                        }
18473                    }
18474                }
18475            }
18476
18477            true
18478        });
18479        self.gutter_highlights
18480            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18481    }
18482
18483    #[cfg(feature = "test-support")]
18484    pub fn all_text_background_highlights(
18485        &self,
18486        window: &mut Window,
18487        cx: &mut Context<Self>,
18488    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18489        let snapshot = self.snapshot(window, cx);
18490        let buffer = &snapshot.buffer_snapshot;
18491        let start = buffer.anchor_before(0);
18492        let end = buffer.anchor_after(buffer.len());
18493        let theme = cx.theme().colors();
18494        self.background_highlights_in_range(start..end, &snapshot, theme)
18495    }
18496
18497    #[cfg(feature = "test-support")]
18498    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18499        let snapshot = self.buffer().read(cx).snapshot(cx);
18500
18501        let highlights = self
18502            .background_highlights
18503            .get(&TypeId::of::<items::BufferSearchHighlights>());
18504
18505        if let Some((_color, ranges)) = highlights {
18506            ranges
18507                .iter()
18508                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18509                .collect_vec()
18510        } else {
18511            vec![]
18512        }
18513    }
18514
18515    fn document_highlights_for_position<'a>(
18516        &'a self,
18517        position: Anchor,
18518        buffer: &'a MultiBufferSnapshot,
18519    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18520        let read_highlights = self
18521            .background_highlights
18522            .get(&TypeId::of::<DocumentHighlightRead>())
18523            .map(|h| &h.1);
18524        let write_highlights = self
18525            .background_highlights
18526            .get(&TypeId::of::<DocumentHighlightWrite>())
18527            .map(|h| &h.1);
18528        let left_position = position.bias_left(buffer);
18529        let right_position = position.bias_right(buffer);
18530        read_highlights
18531            .into_iter()
18532            .chain(write_highlights)
18533            .flat_map(move |ranges| {
18534                let start_ix = match ranges.binary_search_by(|probe| {
18535                    let cmp = probe.end.cmp(&left_position, buffer);
18536                    if cmp.is_ge() {
18537                        Ordering::Greater
18538                    } else {
18539                        Ordering::Less
18540                    }
18541                }) {
18542                    Ok(i) | Err(i) => i,
18543                };
18544
18545                ranges[start_ix..]
18546                    .iter()
18547                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18548            })
18549    }
18550
18551    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18552        self.background_highlights
18553            .get(&TypeId::of::<T>())
18554            .map_or(false, |(_, highlights)| !highlights.is_empty())
18555    }
18556
18557    pub fn background_highlights_in_range(
18558        &self,
18559        search_range: Range<Anchor>,
18560        display_snapshot: &DisplaySnapshot,
18561        theme: &ThemeColors,
18562    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18563        let mut results = Vec::new();
18564        for (color_fetcher, ranges) in self.background_highlights.values() {
18565            let color = color_fetcher(theme);
18566            let start_ix = match ranges.binary_search_by(|probe| {
18567                let cmp = probe
18568                    .end
18569                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18570                if cmp.is_gt() {
18571                    Ordering::Greater
18572                } else {
18573                    Ordering::Less
18574                }
18575            }) {
18576                Ok(i) | Err(i) => i,
18577            };
18578            for range in &ranges[start_ix..] {
18579                if range
18580                    .start
18581                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18582                    .is_ge()
18583                {
18584                    break;
18585                }
18586
18587                let start = range.start.to_display_point(display_snapshot);
18588                let end = range.end.to_display_point(display_snapshot);
18589                results.push((start..end, color))
18590            }
18591        }
18592        results
18593    }
18594
18595    pub fn background_highlight_row_ranges<T: 'static>(
18596        &self,
18597        search_range: Range<Anchor>,
18598        display_snapshot: &DisplaySnapshot,
18599        count: usize,
18600    ) -> Vec<RangeInclusive<DisplayPoint>> {
18601        let mut results = Vec::new();
18602        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18603            return vec![];
18604        };
18605
18606        let start_ix = match ranges.binary_search_by(|probe| {
18607            let cmp = probe
18608                .end
18609                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18610            if cmp.is_gt() {
18611                Ordering::Greater
18612            } else {
18613                Ordering::Less
18614            }
18615        }) {
18616            Ok(i) | Err(i) => i,
18617        };
18618        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18619            if let (Some(start_display), Some(end_display)) = (start, end) {
18620                results.push(
18621                    start_display.to_display_point(display_snapshot)
18622                        ..=end_display.to_display_point(display_snapshot),
18623                );
18624            }
18625        };
18626        let mut start_row: Option<Point> = None;
18627        let mut end_row: Option<Point> = None;
18628        if ranges.len() > count {
18629            return Vec::new();
18630        }
18631        for range in &ranges[start_ix..] {
18632            if range
18633                .start
18634                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18635                .is_ge()
18636            {
18637                break;
18638            }
18639            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18640            if let Some(current_row) = &end_row {
18641                if end.row == current_row.row {
18642                    continue;
18643                }
18644            }
18645            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18646            if start_row.is_none() {
18647                assert_eq!(end_row, None);
18648                start_row = Some(start);
18649                end_row = Some(end);
18650                continue;
18651            }
18652            if let Some(current_end) = end_row.as_mut() {
18653                if start.row > current_end.row + 1 {
18654                    push_region(start_row, end_row);
18655                    start_row = Some(start);
18656                    end_row = Some(end);
18657                } else {
18658                    // Merge two hunks.
18659                    *current_end = end;
18660                }
18661            } else {
18662                unreachable!();
18663            }
18664        }
18665        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18666        push_region(start_row, end_row);
18667        results
18668    }
18669
18670    pub fn gutter_highlights_in_range(
18671        &self,
18672        search_range: Range<Anchor>,
18673        display_snapshot: &DisplaySnapshot,
18674        cx: &App,
18675    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18676        let mut results = Vec::new();
18677        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18678            let color = color_fetcher(cx);
18679            let start_ix = match ranges.binary_search_by(|probe| {
18680                let cmp = probe
18681                    .end
18682                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18683                if cmp.is_gt() {
18684                    Ordering::Greater
18685                } else {
18686                    Ordering::Less
18687                }
18688            }) {
18689                Ok(i) | Err(i) => i,
18690            };
18691            for range in &ranges[start_ix..] {
18692                if range
18693                    .start
18694                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18695                    .is_ge()
18696                {
18697                    break;
18698                }
18699
18700                let start = range.start.to_display_point(display_snapshot);
18701                let end = range.end.to_display_point(display_snapshot);
18702                results.push((start..end, color))
18703            }
18704        }
18705        results
18706    }
18707
18708    /// Get the text ranges corresponding to the redaction query
18709    pub fn redacted_ranges(
18710        &self,
18711        search_range: Range<Anchor>,
18712        display_snapshot: &DisplaySnapshot,
18713        cx: &App,
18714    ) -> Vec<Range<DisplayPoint>> {
18715        display_snapshot
18716            .buffer_snapshot
18717            .redacted_ranges(search_range, |file| {
18718                if let Some(file) = file {
18719                    file.is_private()
18720                        && EditorSettings::get(
18721                            Some(SettingsLocation {
18722                                worktree_id: file.worktree_id(cx),
18723                                path: file.path().as_ref(),
18724                            }),
18725                            cx,
18726                        )
18727                        .redact_private_values
18728                } else {
18729                    false
18730                }
18731            })
18732            .map(|range| {
18733                range.start.to_display_point(display_snapshot)
18734                    ..range.end.to_display_point(display_snapshot)
18735            })
18736            .collect()
18737    }
18738
18739    pub fn highlight_text<T: 'static>(
18740        &mut self,
18741        ranges: Vec<Range<Anchor>>,
18742        style: HighlightStyle,
18743        cx: &mut Context<Self>,
18744    ) {
18745        self.display_map.update(cx, |map, _| {
18746            map.highlight_text(TypeId::of::<T>(), ranges, style)
18747        });
18748        cx.notify();
18749    }
18750
18751    pub(crate) fn highlight_inlays<T: 'static>(
18752        &mut self,
18753        highlights: Vec<InlayHighlight>,
18754        style: HighlightStyle,
18755        cx: &mut Context<Self>,
18756    ) {
18757        self.display_map.update(cx, |map, _| {
18758            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18759        });
18760        cx.notify();
18761    }
18762
18763    pub fn text_highlights<'a, T: 'static>(
18764        &'a self,
18765        cx: &'a App,
18766    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18767        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18768    }
18769
18770    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18771        let cleared = self
18772            .display_map
18773            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18774        if cleared {
18775            cx.notify();
18776        }
18777    }
18778
18779    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18780        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18781            && self.focus_handle.is_focused(window)
18782    }
18783
18784    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18785        self.show_cursor_when_unfocused = is_enabled;
18786        cx.notify();
18787    }
18788
18789    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18790        cx.notify();
18791    }
18792
18793    fn on_debug_session_event(
18794        &mut self,
18795        _session: Entity<Session>,
18796        event: &SessionEvent,
18797        cx: &mut Context<Self>,
18798    ) {
18799        match event {
18800            SessionEvent::InvalidateInlineValue => {
18801                self.refresh_inline_values(cx);
18802            }
18803            _ => {}
18804        }
18805    }
18806
18807    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18808        let Some(project) = self.project.clone() else {
18809            return;
18810        };
18811
18812        if !self.inline_value_cache.enabled {
18813            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18814            self.splice_inlays(&inlays, Vec::new(), cx);
18815            return;
18816        }
18817
18818        let current_execution_position = self
18819            .highlighted_rows
18820            .get(&TypeId::of::<ActiveDebugLine>())
18821            .and_then(|lines| lines.last().map(|line| line.range.start));
18822
18823        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18824            let inline_values = editor
18825                .update(cx, |editor, cx| {
18826                    let Some(current_execution_position) = current_execution_position else {
18827                        return Some(Task::ready(Ok(Vec::new())));
18828                    };
18829
18830                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18831                        let snapshot = buffer.snapshot(cx);
18832
18833                        let excerpt = snapshot.excerpt_containing(
18834                            current_execution_position..current_execution_position,
18835                        )?;
18836
18837                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18838                    })?;
18839
18840                    let range =
18841                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18842
18843                    project.inline_values(buffer, range, cx)
18844                })
18845                .ok()
18846                .flatten()?
18847                .await
18848                .context("refreshing debugger inlays")
18849                .log_err()?;
18850
18851            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18852
18853            for (buffer_id, inline_value) in inline_values
18854                .into_iter()
18855                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18856            {
18857                buffer_inline_values
18858                    .entry(buffer_id)
18859                    .or_default()
18860                    .push(inline_value);
18861            }
18862
18863            editor
18864                .update(cx, |editor, cx| {
18865                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18866                    let mut new_inlays = Vec::default();
18867
18868                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18869                        let buffer_id = buffer_snapshot.remote_id();
18870                        buffer_inline_values
18871                            .get(&buffer_id)
18872                            .into_iter()
18873                            .flatten()
18874                            .for_each(|hint| {
18875                                let inlay = Inlay::debugger_hint(
18876                                    post_inc(&mut editor.next_inlay_id),
18877                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18878                                    hint.text(),
18879                                );
18880
18881                                new_inlays.push(inlay);
18882                            });
18883                    }
18884
18885                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18886                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18887
18888                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18889                })
18890                .ok()?;
18891            Some(())
18892        });
18893    }
18894
18895    fn on_buffer_event(
18896        &mut self,
18897        multibuffer: &Entity<MultiBuffer>,
18898        event: &multi_buffer::Event,
18899        window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) {
18902        match event {
18903            multi_buffer::Event::Edited {
18904                singleton_buffer_edited,
18905                edited_buffer,
18906            } => {
18907                self.scrollbar_marker_state.dirty = true;
18908                self.active_indent_guides_state.dirty = true;
18909                self.refresh_active_diagnostics(cx);
18910                self.refresh_code_actions(window, cx);
18911                self.refresh_selected_text_highlights(true, window, cx);
18912                refresh_matching_bracket_highlights(self, window, cx);
18913                if self.has_active_inline_completion() {
18914                    self.update_visible_inline_completion(window, cx);
18915                }
18916                if let Some(project) = self.project.as_ref() {
18917                    if let Some(edited_buffer) = edited_buffer {
18918                        project.update(cx, |project, cx| {
18919                            self.registered_buffers
18920                                .entry(edited_buffer.read(cx).remote_id())
18921                                .or_insert_with(|| {
18922                                    project
18923                                        .register_buffer_with_language_servers(&edited_buffer, cx)
18924                                });
18925                        });
18926                        if edited_buffer.read(cx).file().is_some() {
18927                            self.pull_diagnostics(
18928                                Some(edited_buffer.read(cx).remote_id()),
18929                                window,
18930                                cx,
18931                            );
18932                        }
18933                    }
18934                }
18935                cx.emit(EditorEvent::BufferEdited);
18936                cx.emit(SearchEvent::MatchesInvalidated);
18937                if *singleton_buffer_edited {
18938                    if let Some(buffer) = edited_buffer {
18939                        if buffer.read(cx).file().is_none() {
18940                            cx.emit(EditorEvent::TitleChanged);
18941                        }
18942                    }
18943                    if let Some(project) = &self.project {
18944                        #[allow(clippy::mutable_key_type)]
18945                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18946                            multibuffer
18947                                .all_buffers()
18948                                .into_iter()
18949                                .filter_map(|buffer| {
18950                                    buffer.update(cx, |buffer, cx| {
18951                                        let language = buffer.language()?;
18952                                        let should_discard = project.update(cx, |project, cx| {
18953                                            project.is_local()
18954                                                && !project.has_language_servers_for(buffer, cx)
18955                                        });
18956                                        should_discard.not().then_some(language.clone())
18957                                    })
18958                                })
18959                                .collect::<HashSet<_>>()
18960                        });
18961                        if !languages_affected.is_empty() {
18962                            self.refresh_inlay_hints(
18963                                InlayHintRefreshReason::BufferEdited(languages_affected),
18964                                cx,
18965                            );
18966                        }
18967                    }
18968                }
18969
18970                let Some(project) = &self.project else { return };
18971                let (telemetry, is_via_ssh) = {
18972                    let project = project.read(cx);
18973                    let telemetry = project.client().telemetry().clone();
18974                    let is_via_ssh = project.is_via_ssh();
18975                    (telemetry, is_via_ssh)
18976                };
18977                refresh_linked_ranges(self, window, cx);
18978                telemetry.log_edit_event("editor", is_via_ssh);
18979            }
18980            multi_buffer::Event::ExcerptsAdded {
18981                buffer,
18982                predecessor,
18983                excerpts,
18984            } => {
18985                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18986                let buffer_id = buffer.read(cx).remote_id();
18987                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18988                    if let Some(project) = &self.project {
18989                        update_uncommitted_diff_for_buffer(
18990                            cx.entity(),
18991                            project,
18992                            [buffer.clone()],
18993                            self.buffer.clone(),
18994                            cx,
18995                        )
18996                        .detach();
18997                    }
18998                }
18999                cx.emit(EditorEvent::ExcerptsAdded {
19000                    buffer: buffer.clone(),
19001                    predecessor: *predecessor,
19002                    excerpts: excerpts.clone(),
19003                });
19004                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19005            }
19006            multi_buffer::Event::ExcerptsRemoved {
19007                ids,
19008                removed_buffer_ids,
19009            } => {
19010                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19011                let buffer = self.buffer.read(cx);
19012                self.registered_buffers
19013                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19014                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19015                cx.emit(EditorEvent::ExcerptsRemoved {
19016                    ids: ids.clone(),
19017                    removed_buffer_ids: removed_buffer_ids.clone(),
19018                })
19019            }
19020            multi_buffer::Event::ExcerptsEdited {
19021                excerpt_ids,
19022                buffer_ids,
19023            } => {
19024                self.display_map.update(cx, |map, cx| {
19025                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19026                });
19027                cx.emit(EditorEvent::ExcerptsEdited {
19028                    ids: excerpt_ids.clone(),
19029                })
19030            }
19031            multi_buffer::Event::ExcerptsExpanded { ids } => {
19032                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19033                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19034            }
19035            multi_buffer::Event::Reparsed(buffer_id) => {
19036                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19037                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19038
19039                cx.emit(EditorEvent::Reparsed(*buffer_id));
19040            }
19041            multi_buffer::Event::DiffHunksToggled => {
19042                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19043            }
19044            multi_buffer::Event::LanguageChanged(buffer_id) => {
19045                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19046                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19047                cx.emit(EditorEvent::Reparsed(*buffer_id));
19048                cx.notify();
19049            }
19050            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19051            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19052            multi_buffer::Event::FileHandleChanged
19053            | multi_buffer::Event::Reloaded
19054            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19055            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19056            multi_buffer::Event::DiagnosticsUpdated => {
19057                self.update_diagnostics_state(window, cx);
19058            }
19059            _ => {}
19060        };
19061    }
19062
19063    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19064        self.refresh_active_diagnostics(cx);
19065        self.refresh_inline_diagnostics(true, window, cx);
19066        self.scrollbar_marker_state.dirty = true;
19067        cx.notify();
19068    }
19069
19070    pub fn start_temporary_diff_override(&mut self) {
19071        self.load_diff_task.take();
19072        self.temporary_diff_override = true;
19073    }
19074
19075    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19076        self.temporary_diff_override = false;
19077        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19078        self.buffer.update(cx, |buffer, cx| {
19079            buffer.set_all_diff_hunks_collapsed(cx);
19080        });
19081
19082        if let Some(project) = self.project.clone() {
19083            self.load_diff_task = Some(
19084                update_uncommitted_diff_for_buffer(
19085                    cx.entity(),
19086                    &project,
19087                    self.buffer.read(cx).all_buffers(),
19088                    self.buffer.clone(),
19089                    cx,
19090                )
19091                .shared(),
19092            );
19093        }
19094    }
19095
19096    fn on_display_map_changed(
19097        &mut self,
19098        _: Entity<DisplayMap>,
19099        _: &mut Window,
19100        cx: &mut Context<Self>,
19101    ) {
19102        cx.notify();
19103    }
19104
19105    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19106        let new_severity = if self.diagnostics_enabled() {
19107            EditorSettings::get_global(cx)
19108                .diagnostics_max_severity
19109                .unwrap_or(DiagnosticSeverity::Hint)
19110        } else {
19111            DiagnosticSeverity::Off
19112        };
19113        self.set_max_diagnostics_severity(new_severity, cx);
19114        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19115        self.update_edit_prediction_settings(cx);
19116        self.refresh_inline_completion(true, false, window, cx);
19117        self.refresh_inlay_hints(
19118            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19119                self.selections.newest_anchor().head(),
19120                &self.buffer.read(cx).snapshot(cx),
19121                cx,
19122            )),
19123            cx,
19124        );
19125
19126        let old_cursor_shape = self.cursor_shape;
19127
19128        {
19129            let editor_settings = EditorSettings::get_global(cx);
19130            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19131            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19132            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19133            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19134            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19135        }
19136
19137        if old_cursor_shape != self.cursor_shape {
19138            cx.emit(EditorEvent::CursorShapeChanged);
19139        }
19140
19141        let project_settings = ProjectSettings::get_global(cx);
19142        self.serialize_dirty_buffers =
19143            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19144
19145        if self.mode.is_full() {
19146            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19147            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19148            if self.show_inline_diagnostics != show_inline_diagnostics {
19149                self.show_inline_diagnostics = show_inline_diagnostics;
19150                self.refresh_inline_diagnostics(false, window, cx);
19151            }
19152
19153            if self.git_blame_inline_enabled != inline_blame_enabled {
19154                self.toggle_git_blame_inline_internal(false, window, cx);
19155            }
19156
19157            let minimap_settings = EditorSettings::get_global(cx).minimap;
19158            if self.minimap_visibility != MinimapVisibility::Disabled {
19159                if self.minimap_visibility.settings_visibility()
19160                    != minimap_settings.minimap_enabled()
19161                {
19162                    self.set_minimap_visibility(
19163                        MinimapVisibility::for_mode(self.mode(), cx),
19164                        window,
19165                        cx,
19166                    );
19167                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19168                    minimap_entity.update(cx, |minimap_editor, cx| {
19169                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19170                    })
19171                }
19172            }
19173        }
19174
19175        cx.notify();
19176    }
19177
19178    pub fn set_searchable(&mut self, searchable: bool) {
19179        self.searchable = searchable;
19180    }
19181
19182    pub fn searchable(&self) -> bool {
19183        self.searchable
19184    }
19185
19186    fn open_proposed_changes_editor(
19187        &mut self,
19188        _: &OpenProposedChangesEditor,
19189        window: &mut Window,
19190        cx: &mut Context<Self>,
19191    ) {
19192        let Some(workspace) = self.workspace() else {
19193            cx.propagate();
19194            return;
19195        };
19196
19197        let selections = self.selections.all::<usize>(cx);
19198        let multi_buffer = self.buffer.read(cx);
19199        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19200        let mut new_selections_by_buffer = HashMap::default();
19201        for selection in selections {
19202            for (buffer, range, _) in
19203                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19204            {
19205                let mut range = range.to_point(buffer);
19206                range.start.column = 0;
19207                range.end.column = buffer.line_len(range.end.row);
19208                new_selections_by_buffer
19209                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19210                    .or_insert(Vec::new())
19211                    .push(range)
19212            }
19213        }
19214
19215        let proposed_changes_buffers = new_selections_by_buffer
19216            .into_iter()
19217            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19218            .collect::<Vec<_>>();
19219        let proposed_changes_editor = cx.new(|cx| {
19220            ProposedChangesEditor::new(
19221                "Proposed changes",
19222                proposed_changes_buffers,
19223                self.project.clone(),
19224                window,
19225                cx,
19226            )
19227        });
19228
19229        window.defer(cx, move |window, cx| {
19230            workspace.update(cx, |workspace, cx| {
19231                workspace.active_pane().update(cx, |pane, cx| {
19232                    pane.add_item(
19233                        Box::new(proposed_changes_editor),
19234                        true,
19235                        true,
19236                        None,
19237                        window,
19238                        cx,
19239                    );
19240                });
19241            });
19242        });
19243    }
19244
19245    pub fn open_excerpts_in_split(
19246        &mut self,
19247        _: &OpenExcerptsSplit,
19248        window: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        self.open_excerpts_common(None, true, window, cx)
19252    }
19253
19254    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19255        self.open_excerpts_common(None, false, window, cx)
19256    }
19257
19258    fn open_excerpts_common(
19259        &mut self,
19260        jump_data: Option<JumpData>,
19261        split: bool,
19262        window: &mut Window,
19263        cx: &mut Context<Self>,
19264    ) {
19265        let Some(workspace) = self.workspace() else {
19266            cx.propagate();
19267            return;
19268        };
19269
19270        if self.buffer.read(cx).is_singleton() {
19271            cx.propagate();
19272            return;
19273        }
19274
19275        let mut new_selections_by_buffer = HashMap::default();
19276        match &jump_data {
19277            Some(JumpData::MultiBufferPoint {
19278                excerpt_id,
19279                position,
19280                anchor,
19281                line_offset_from_top,
19282            }) => {
19283                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19284                if let Some(buffer) = multi_buffer_snapshot
19285                    .buffer_id_for_excerpt(*excerpt_id)
19286                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19287                {
19288                    let buffer_snapshot = buffer.read(cx).snapshot();
19289                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19290                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19291                    } else {
19292                        buffer_snapshot.clip_point(*position, Bias::Left)
19293                    };
19294                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19295                    new_selections_by_buffer.insert(
19296                        buffer,
19297                        (
19298                            vec![jump_to_offset..jump_to_offset],
19299                            Some(*line_offset_from_top),
19300                        ),
19301                    );
19302                }
19303            }
19304            Some(JumpData::MultiBufferRow {
19305                row,
19306                line_offset_from_top,
19307            }) => {
19308                let point = MultiBufferPoint::new(row.0, 0);
19309                if let Some((buffer, buffer_point, _)) =
19310                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19311                {
19312                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19313                    new_selections_by_buffer
19314                        .entry(buffer)
19315                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19316                        .0
19317                        .push(buffer_offset..buffer_offset)
19318                }
19319            }
19320            None => {
19321                let selections = self.selections.all::<usize>(cx);
19322                let multi_buffer = self.buffer.read(cx);
19323                for selection in selections {
19324                    for (snapshot, range, _, anchor) in multi_buffer
19325                        .snapshot(cx)
19326                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19327                    {
19328                        if let Some(anchor) = anchor {
19329                            // selection is in a deleted hunk
19330                            let Some(buffer_id) = anchor.buffer_id else {
19331                                continue;
19332                            };
19333                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19334                                continue;
19335                            };
19336                            let offset = text::ToOffset::to_offset(
19337                                &anchor.text_anchor,
19338                                &buffer_handle.read(cx).snapshot(),
19339                            );
19340                            let range = offset..offset;
19341                            new_selections_by_buffer
19342                                .entry(buffer_handle)
19343                                .or_insert((Vec::new(), None))
19344                                .0
19345                                .push(range)
19346                        } else {
19347                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19348                            else {
19349                                continue;
19350                            };
19351                            new_selections_by_buffer
19352                                .entry(buffer_handle)
19353                                .or_insert((Vec::new(), None))
19354                                .0
19355                                .push(range)
19356                        }
19357                    }
19358                }
19359            }
19360        }
19361
19362        new_selections_by_buffer
19363            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19364
19365        if new_selections_by_buffer.is_empty() {
19366            return;
19367        }
19368
19369        // We defer the pane interaction because we ourselves are a workspace item
19370        // and activating a new item causes the pane to call a method on us reentrantly,
19371        // which panics if we're on the stack.
19372        window.defer(cx, move |window, cx| {
19373            workspace.update(cx, |workspace, cx| {
19374                let pane = if split {
19375                    workspace.adjacent_pane(window, cx)
19376                } else {
19377                    workspace.active_pane().clone()
19378                };
19379
19380                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19381                    let editor = buffer
19382                        .read(cx)
19383                        .file()
19384                        .is_none()
19385                        .then(|| {
19386                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19387                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19388                            // Instead, we try to activate the existing editor in the pane first.
19389                            let (editor, pane_item_index) =
19390                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19391                                    let editor = item.downcast::<Editor>()?;
19392                                    let singleton_buffer =
19393                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19394                                    if singleton_buffer == buffer {
19395                                        Some((editor, i))
19396                                    } else {
19397                                        None
19398                                    }
19399                                })?;
19400                            pane.update(cx, |pane, cx| {
19401                                pane.activate_item(pane_item_index, true, true, window, cx)
19402                            });
19403                            Some(editor)
19404                        })
19405                        .flatten()
19406                        .unwrap_or_else(|| {
19407                            workspace.open_project_item::<Self>(
19408                                pane.clone(),
19409                                buffer,
19410                                true,
19411                                true,
19412                                window,
19413                                cx,
19414                            )
19415                        });
19416
19417                    editor.update(cx, |editor, cx| {
19418                        let autoscroll = match scroll_offset {
19419                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19420                            None => Autoscroll::newest(),
19421                        };
19422                        let nav_history = editor.nav_history.take();
19423                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19424                            s.select_ranges(ranges);
19425                        });
19426                        editor.nav_history = nav_history;
19427                    });
19428                }
19429            })
19430        });
19431    }
19432
19433    // For now, don't allow opening excerpts in buffers that aren't backed by
19434    // regular project files.
19435    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19436        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19437    }
19438
19439    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19440        let snapshot = self.buffer.read(cx).read(cx);
19441        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19442        Some(
19443            ranges
19444                .iter()
19445                .map(move |range| {
19446                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19447                })
19448                .collect(),
19449        )
19450    }
19451
19452    fn selection_replacement_ranges(
19453        &self,
19454        range: Range<OffsetUtf16>,
19455        cx: &mut App,
19456    ) -> Vec<Range<OffsetUtf16>> {
19457        let selections = self.selections.all::<OffsetUtf16>(cx);
19458        let newest_selection = selections
19459            .iter()
19460            .max_by_key(|selection| selection.id)
19461            .unwrap();
19462        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19463        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19464        let snapshot = self.buffer.read(cx).read(cx);
19465        selections
19466            .into_iter()
19467            .map(|mut selection| {
19468                selection.start.0 =
19469                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19470                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19471                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19472                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19473            })
19474            .collect()
19475    }
19476
19477    fn report_editor_event(
19478        &self,
19479        event_type: &'static str,
19480        file_extension: Option<String>,
19481        cx: &App,
19482    ) {
19483        if cfg!(any(test, feature = "test-support")) {
19484            return;
19485        }
19486
19487        let Some(project) = &self.project else { return };
19488
19489        // If None, we are in a file without an extension
19490        let file = self
19491            .buffer
19492            .read(cx)
19493            .as_singleton()
19494            .and_then(|b| b.read(cx).file());
19495        let file_extension = file_extension.or(file
19496            .as_ref()
19497            .and_then(|file| Path::new(file.file_name(cx)).extension())
19498            .and_then(|e| e.to_str())
19499            .map(|a| a.to_string()));
19500
19501        let vim_mode = vim_enabled(cx);
19502
19503        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19504        let copilot_enabled = edit_predictions_provider
19505            == language::language_settings::EditPredictionProvider::Copilot;
19506        let copilot_enabled_for_language = self
19507            .buffer
19508            .read(cx)
19509            .language_settings(cx)
19510            .show_edit_predictions;
19511
19512        let project = project.read(cx);
19513        telemetry::event!(
19514            event_type,
19515            file_extension,
19516            vim_mode,
19517            copilot_enabled,
19518            copilot_enabled_for_language,
19519            edit_predictions_provider,
19520            is_via_ssh = project.is_via_ssh(),
19521        );
19522    }
19523
19524    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19525    /// with each line being an array of {text, highlight} objects.
19526    fn copy_highlight_json(
19527        &mut self,
19528        _: &CopyHighlightJson,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) {
19532        #[derive(Serialize)]
19533        struct Chunk<'a> {
19534            text: String,
19535            highlight: Option<&'a str>,
19536        }
19537
19538        let snapshot = self.buffer.read(cx).snapshot(cx);
19539        let range = self
19540            .selected_text_range(false, window, cx)
19541            .and_then(|selection| {
19542                if selection.range.is_empty() {
19543                    None
19544                } else {
19545                    Some(selection.range)
19546                }
19547            })
19548            .unwrap_or_else(|| 0..snapshot.len());
19549
19550        let chunks = snapshot.chunks(range, true);
19551        let mut lines = Vec::new();
19552        let mut line: VecDeque<Chunk> = VecDeque::new();
19553
19554        let Some(style) = self.style.as_ref() else {
19555            return;
19556        };
19557
19558        for chunk in chunks {
19559            let highlight = chunk
19560                .syntax_highlight_id
19561                .and_then(|id| id.name(&style.syntax));
19562            let mut chunk_lines = chunk.text.split('\n').peekable();
19563            while let Some(text) = chunk_lines.next() {
19564                let mut merged_with_last_token = false;
19565                if let Some(last_token) = line.back_mut() {
19566                    if last_token.highlight == highlight {
19567                        last_token.text.push_str(text);
19568                        merged_with_last_token = true;
19569                    }
19570                }
19571
19572                if !merged_with_last_token {
19573                    line.push_back(Chunk {
19574                        text: text.into(),
19575                        highlight,
19576                    });
19577                }
19578
19579                if chunk_lines.peek().is_some() {
19580                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19581                        line.pop_front();
19582                    }
19583                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19584                        line.pop_back();
19585                    }
19586
19587                    lines.push(mem::take(&mut line));
19588                }
19589            }
19590        }
19591
19592        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19593            return;
19594        };
19595        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19596    }
19597
19598    pub fn open_context_menu(
19599        &mut self,
19600        _: &OpenContextMenu,
19601        window: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        self.request_autoscroll(Autoscroll::newest(), cx);
19605        let position = self.selections.newest_display(cx).start;
19606        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19607    }
19608
19609    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19610        &self.inlay_hint_cache
19611    }
19612
19613    pub fn replay_insert_event(
19614        &mut self,
19615        text: &str,
19616        relative_utf16_range: Option<Range<isize>>,
19617        window: &mut Window,
19618        cx: &mut Context<Self>,
19619    ) {
19620        if !self.input_enabled {
19621            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19622            return;
19623        }
19624        if let Some(relative_utf16_range) = relative_utf16_range {
19625            let selections = self.selections.all::<OffsetUtf16>(cx);
19626            self.change_selections(None, window, cx, |s| {
19627                let new_ranges = selections.into_iter().map(|range| {
19628                    let start = OffsetUtf16(
19629                        range
19630                            .head()
19631                            .0
19632                            .saturating_add_signed(relative_utf16_range.start),
19633                    );
19634                    let end = OffsetUtf16(
19635                        range
19636                            .head()
19637                            .0
19638                            .saturating_add_signed(relative_utf16_range.end),
19639                    );
19640                    start..end
19641                });
19642                s.select_ranges(new_ranges);
19643            });
19644        }
19645
19646        self.handle_input(text, window, cx);
19647    }
19648
19649    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19650        let Some(provider) = self.semantics_provider.as_ref() else {
19651            return false;
19652        };
19653
19654        let mut supports = false;
19655        self.buffer().update(cx, |this, cx| {
19656            this.for_each_buffer(|buffer| {
19657                supports |= provider.supports_inlay_hints(buffer, cx);
19658            });
19659        });
19660
19661        supports
19662    }
19663
19664    pub fn is_focused(&self, window: &Window) -> bool {
19665        self.focus_handle.is_focused(window)
19666    }
19667
19668    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19669        cx.emit(EditorEvent::Focused);
19670
19671        if let Some(descendant) = self
19672            .last_focused_descendant
19673            .take()
19674            .and_then(|descendant| descendant.upgrade())
19675        {
19676            window.focus(&descendant);
19677        } else {
19678            if let Some(blame) = self.blame.as_ref() {
19679                blame.update(cx, GitBlame::focus)
19680            }
19681
19682            self.blink_manager.update(cx, BlinkManager::enable);
19683            self.show_cursor_names(window, cx);
19684            self.buffer.update(cx, |buffer, cx| {
19685                buffer.finalize_last_transaction(cx);
19686                if self.leader_id.is_none() {
19687                    buffer.set_active_selections(
19688                        &self.selections.disjoint_anchors(),
19689                        self.selections.line_mode,
19690                        self.cursor_shape,
19691                        cx,
19692                    );
19693                }
19694            });
19695        }
19696    }
19697
19698    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19699        cx.emit(EditorEvent::FocusedIn)
19700    }
19701
19702    fn handle_focus_out(
19703        &mut self,
19704        event: FocusOutEvent,
19705        _window: &mut Window,
19706        cx: &mut Context<Self>,
19707    ) {
19708        if event.blurred != self.focus_handle {
19709            self.last_focused_descendant = Some(event.blurred);
19710        }
19711        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19712    }
19713
19714    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19715        self.blink_manager.update(cx, BlinkManager::disable);
19716        self.buffer
19717            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19718
19719        if let Some(blame) = self.blame.as_ref() {
19720            blame.update(cx, GitBlame::blur)
19721        }
19722        if !self.hover_state.focused(window, cx) {
19723            hide_hover(self, cx);
19724        }
19725        if !self
19726            .context_menu
19727            .borrow()
19728            .as_ref()
19729            .is_some_and(|context_menu| context_menu.focused(window, cx))
19730        {
19731            self.hide_context_menu(window, cx);
19732        }
19733        self.discard_inline_completion(false, cx);
19734        cx.emit(EditorEvent::Blurred);
19735        cx.notify();
19736    }
19737
19738    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19739        let mut pending: String = window
19740            .pending_input_keystrokes()
19741            .into_iter()
19742            .flatten()
19743            .filter_map(|keystroke| {
19744                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
19745                    Some(keystroke.key_char.clone().unwrap_or(keystroke.key.clone()))
19746                } else {
19747                    None
19748                }
19749            })
19750            .collect();
19751
19752        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
19753            pending = "".to_string();
19754        }
19755
19756        let existing_pending = self
19757            .text_highlights::<PendingInput>(cx)
19758            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
19759        if existing_pending.is_none() && pending.is_empty() {
19760            return;
19761        }
19762        let transaction =
19763            self.transact(window, cx, |this, window, cx| {
19764                let selections = this.selections.all::<usize>(cx);
19765                let edits = selections
19766                    .iter()
19767                    .map(|selection| (selection.end..selection.end, pending.clone()));
19768                this.edit(edits, cx);
19769                this.change_selections(None, window, cx, |s| {
19770                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
19771                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
19772                    }));
19773                });
19774                if let Some(existing_ranges) = existing_pending {
19775                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
19776                    this.edit(edits, cx);
19777                }
19778            });
19779
19780        let snapshot = self.snapshot(window, cx);
19781        let ranges = self
19782            .selections
19783            .all::<usize>(cx)
19784            .into_iter()
19785            .map(|selection| {
19786                snapshot.buffer_snapshot.anchor_after(selection.end)
19787                    ..snapshot
19788                        .buffer_snapshot
19789                        .anchor_before(selection.end + pending.len())
19790            })
19791            .collect();
19792
19793        if pending.is_empty() {
19794            self.clear_highlights::<PendingInput>(cx);
19795        } else {
19796            self.highlight_text::<PendingInput>(
19797                ranges,
19798                HighlightStyle {
19799                    underline: Some(UnderlineStyle {
19800                        thickness: px(1.),
19801                        color: None,
19802                        wavy: false,
19803                    }),
19804                    ..Default::default()
19805                },
19806                cx,
19807            );
19808        }
19809
19810        self.ime_transaction = self.ime_transaction.or(transaction);
19811        if let Some(transaction) = self.ime_transaction {
19812            self.buffer.update(cx, |buffer, cx| {
19813                buffer.group_until_transaction(transaction, cx);
19814            });
19815        }
19816
19817        if self.text_highlights::<PendingInput>(cx).is_none() {
19818            self.ime_transaction.take();
19819        }
19820    }
19821
19822    pub fn register_action<A: Action>(
19823        &mut self,
19824        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19825    ) -> Subscription {
19826        let id = self.next_editor_action_id.post_inc();
19827        let listener = Arc::new(listener);
19828        self.editor_actions.borrow_mut().insert(
19829            id,
19830            Box::new(move |window, _| {
19831                let listener = listener.clone();
19832                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19833                    let action = action.downcast_ref().unwrap();
19834                    if phase == DispatchPhase::Bubble {
19835                        listener(action, window, cx)
19836                    }
19837                })
19838            }),
19839        );
19840
19841        let editor_actions = self.editor_actions.clone();
19842        Subscription::new(move || {
19843            editor_actions.borrow_mut().remove(&id);
19844        })
19845    }
19846
19847    pub fn file_header_size(&self) -> u32 {
19848        FILE_HEADER_HEIGHT
19849    }
19850
19851    pub fn restore(
19852        &mut self,
19853        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19854        window: &mut Window,
19855        cx: &mut Context<Self>,
19856    ) {
19857        let workspace = self.workspace();
19858        let project = self.project.as_ref();
19859        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19860            let mut tasks = Vec::new();
19861            for (buffer_id, changes) in revert_changes {
19862                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19863                    buffer.update(cx, |buffer, cx| {
19864                        buffer.edit(
19865                            changes
19866                                .into_iter()
19867                                .map(|(range, text)| (range, text.to_string())),
19868                            None,
19869                            cx,
19870                        );
19871                    });
19872
19873                    if let Some(project) =
19874                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19875                    {
19876                        project.update(cx, |project, cx| {
19877                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19878                        })
19879                    }
19880                }
19881            }
19882            tasks
19883        });
19884        cx.spawn_in(window, async move |_, cx| {
19885            for (buffer, task) in save_tasks {
19886                let result = task.await;
19887                if result.is_err() {
19888                    let Some(path) = buffer
19889                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19890                        .ok()
19891                    else {
19892                        continue;
19893                    };
19894                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19895                        let Some(task) = cx
19896                            .update_window_entity(&workspace, |workspace, window, cx| {
19897                                workspace
19898                                    .open_path_preview(path, None, false, false, false, window, cx)
19899                            })
19900                            .ok()
19901                        else {
19902                            continue;
19903                        };
19904                        task.await.log_err();
19905                    }
19906                }
19907            }
19908        })
19909        .detach();
19910        self.change_selections(None, window, cx, |selections| selections.refresh());
19911    }
19912
19913    pub fn to_pixel_point(
19914        &self,
19915        source: multi_buffer::Anchor,
19916        editor_snapshot: &EditorSnapshot,
19917        window: &mut Window,
19918    ) -> Option<gpui::Point<Pixels>> {
19919        let source_point = source.to_display_point(editor_snapshot);
19920        self.display_to_pixel_point(source_point, editor_snapshot, window)
19921    }
19922
19923    pub fn display_to_pixel_point(
19924        &self,
19925        source: DisplayPoint,
19926        editor_snapshot: &EditorSnapshot,
19927        window: &mut Window,
19928    ) -> Option<gpui::Point<Pixels>> {
19929        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19930        let text_layout_details = self.text_layout_details(window);
19931        let scroll_top = text_layout_details
19932            .scroll_anchor
19933            .scroll_position(editor_snapshot)
19934            .y;
19935
19936        if source.row().as_f32() < scroll_top.floor() {
19937            return None;
19938        }
19939        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19940        let source_y = line_height * (source.row().as_f32() - scroll_top);
19941        Some(gpui::Point::new(source_x, source_y))
19942    }
19943
19944    pub fn has_visible_completions_menu(&self) -> bool {
19945        !self.edit_prediction_preview_is_active()
19946            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19947                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19948            })
19949    }
19950
19951    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19952        if self.mode.is_minimap() {
19953            return;
19954        }
19955        self.addons
19956            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19957    }
19958
19959    pub fn unregister_addon<T: Addon>(&mut self) {
19960        self.addons.remove(&std::any::TypeId::of::<T>());
19961    }
19962
19963    pub fn addon<T: Addon>(&self) -> Option<&T> {
19964        let type_id = std::any::TypeId::of::<T>();
19965        self.addons
19966            .get(&type_id)
19967            .and_then(|item| item.to_any().downcast_ref::<T>())
19968    }
19969
19970    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19971        let type_id = std::any::TypeId::of::<T>();
19972        self.addons
19973            .get_mut(&type_id)
19974            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19975    }
19976
19977    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19978        let text_layout_details = self.text_layout_details(window);
19979        let style = &text_layout_details.editor_style;
19980        let font_id = window.text_system().resolve_font(&style.text.font());
19981        let font_size = style.text.font_size.to_pixels(window.rem_size());
19982        let line_height = style.text.line_height_in_pixels(window.rem_size());
19983        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19984
19985        gpui::Size::new(em_width, line_height)
19986    }
19987
19988    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19989        self.load_diff_task.clone()
19990    }
19991
19992    fn read_metadata_from_db(
19993        &mut self,
19994        item_id: u64,
19995        workspace_id: WorkspaceId,
19996        window: &mut Window,
19997        cx: &mut Context<Editor>,
19998    ) {
19999        if self.is_singleton(cx)
20000            && !self.mode.is_minimap()
20001            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20002        {
20003            let buffer_snapshot = OnceCell::new();
20004
20005            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20006                if !folds.is_empty() {
20007                    let snapshot =
20008                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20009                    self.fold_ranges(
20010                        folds
20011                            .into_iter()
20012                            .map(|(start, end)| {
20013                                snapshot.clip_offset(start, Bias::Left)
20014                                    ..snapshot.clip_offset(end, Bias::Right)
20015                            })
20016                            .collect(),
20017                        false,
20018                        window,
20019                        cx,
20020                    );
20021                }
20022            }
20023
20024            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20025                if !selections.is_empty() {
20026                    let snapshot =
20027                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20028                    // skip adding the initial selection to selection history
20029                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20030                    self.change_selections(None, window, cx, |s| {
20031                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20032                            snapshot.clip_offset(start, Bias::Left)
20033                                ..snapshot.clip_offset(end, Bias::Right)
20034                        }));
20035                    });
20036                    self.selection_history.mode = SelectionHistoryMode::Normal;
20037                }
20038            };
20039        }
20040
20041        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20042    }
20043}
20044
20045fn vim_enabled(cx: &App) -> bool {
20046    cx.global::<SettingsStore>()
20047        .raw_user_settings()
20048        .get("vim_mode")
20049        == Some(&serde_json::Value::Bool(true))
20050}
20051
20052fn process_completion_for_edit(
20053    completion: &Completion,
20054    intent: CompletionIntent,
20055    buffer: &Entity<Buffer>,
20056    cursor_position: &text::Anchor,
20057    cx: &mut Context<Editor>,
20058) -> CompletionEdit {
20059    let buffer = buffer.read(cx);
20060    let buffer_snapshot = buffer.snapshot();
20061    let (snippet, new_text) = if completion.is_snippet() {
20062        let mut snippet_source = completion.new_text.clone();
20063        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
20064            if scope.prefers_label_for_snippet_in_completion() {
20065                if let Some(label) = completion.label() {
20066                    if matches!(
20067                        completion.kind(),
20068                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20069                    ) {
20070                        snippet_source = label;
20071                    }
20072                }
20073            }
20074        }
20075        match Snippet::parse(&snippet_source).log_err() {
20076            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20077            None => (None, completion.new_text.clone()),
20078        }
20079    } else {
20080        (None, completion.new_text.clone())
20081    };
20082
20083    let mut range_to_replace = {
20084        let replace_range = &completion.replace_range;
20085        if let CompletionSource::Lsp {
20086            insert_range: Some(insert_range),
20087            ..
20088        } = &completion.source
20089        {
20090            debug_assert_eq!(
20091                insert_range.start, replace_range.start,
20092                "insert_range and replace_range should start at the same position"
20093            );
20094            debug_assert!(
20095                insert_range
20096                    .start
20097                    .cmp(&cursor_position, &buffer_snapshot)
20098                    .is_le(),
20099                "insert_range should start before or at cursor position"
20100            );
20101            debug_assert!(
20102                replace_range
20103                    .start
20104                    .cmp(&cursor_position, &buffer_snapshot)
20105                    .is_le(),
20106                "replace_range should start before or at cursor position"
20107            );
20108            debug_assert!(
20109                insert_range
20110                    .end
20111                    .cmp(&cursor_position, &buffer_snapshot)
20112                    .is_le(),
20113                "insert_range should end before or at cursor position"
20114            );
20115
20116            let should_replace = match intent {
20117                CompletionIntent::CompleteWithInsert => false,
20118                CompletionIntent::CompleteWithReplace => true,
20119                CompletionIntent::Complete | CompletionIntent::Compose => {
20120                    let insert_mode =
20121                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20122                            .completions
20123                            .lsp_insert_mode;
20124                    match insert_mode {
20125                        LspInsertMode::Insert => false,
20126                        LspInsertMode::Replace => true,
20127                        LspInsertMode::ReplaceSubsequence => {
20128                            let mut text_to_replace = buffer.chars_for_range(
20129                                buffer.anchor_before(replace_range.start)
20130                                    ..buffer.anchor_after(replace_range.end),
20131                            );
20132                            let mut current_needle = text_to_replace.next();
20133                            for haystack_ch in completion.label.text.chars() {
20134                                if let Some(needle_ch) = current_needle {
20135                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20136                                        current_needle = text_to_replace.next();
20137                                    }
20138                                }
20139                            }
20140                            current_needle.is_none()
20141                        }
20142                        LspInsertMode::ReplaceSuffix => {
20143                            if replace_range
20144                                .end
20145                                .cmp(&cursor_position, &buffer_snapshot)
20146                                .is_gt()
20147                            {
20148                                let range_after_cursor = *cursor_position..replace_range.end;
20149                                let text_after_cursor = buffer
20150                                    .text_for_range(
20151                                        buffer.anchor_before(range_after_cursor.start)
20152                                            ..buffer.anchor_after(range_after_cursor.end),
20153                                    )
20154                                    .collect::<String>()
20155                                    .to_ascii_lowercase();
20156                                completion
20157                                    .label
20158                                    .text
20159                                    .to_ascii_lowercase()
20160                                    .ends_with(&text_after_cursor)
20161                            } else {
20162                                true
20163                            }
20164                        }
20165                    }
20166                }
20167            };
20168
20169            if should_replace {
20170                replace_range.clone()
20171            } else {
20172                insert_range.clone()
20173            }
20174        } else {
20175            replace_range.clone()
20176        }
20177    };
20178
20179    if range_to_replace
20180        .end
20181        .cmp(&cursor_position, &buffer_snapshot)
20182        .is_lt()
20183    {
20184        range_to_replace.end = *cursor_position;
20185    }
20186
20187    CompletionEdit {
20188        new_text,
20189        replace_range: range_to_replace.to_offset(&buffer),
20190        snippet,
20191    }
20192}
20193
20194struct CompletionEdit {
20195    new_text: String,
20196    replace_range: Range<usize>,
20197    snippet: Option<Snippet>,
20198}
20199
20200fn insert_extra_newline_brackets(
20201    buffer: &MultiBufferSnapshot,
20202    range: Range<usize>,
20203    language: &language::LanguageScope,
20204) -> bool {
20205    let leading_whitespace_len = buffer
20206        .reversed_chars_at(range.start)
20207        .take_while(|c| c.is_whitespace() && *c != '\n')
20208        .map(|c| c.len_utf8())
20209        .sum::<usize>();
20210    let trailing_whitespace_len = buffer
20211        .chars_at(range.end)
20212        .take_while(|c| c.is_whitespace() && *c != '\n')
20213        .map(|c| c.len_utf8())
20214        .sum::<usize>();
20215    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20216
20217    language.brackets().any(|(pair, enabled)| {
20218        let pair_start = pair.start.trim_end();
20219        let pair_end = pair.end.trim_start();
20220
20221        enabled
20222            && pair.newline
20223            && buffer.contains_str_at(range.end, pair_end)
20224            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20225    })
20226}
20227
20228fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20229    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20230        [(buffer, range, _)] => (*buffer, range.clone()),
20231        _ => return false,
20232    };
20233    let pair = {
20234        let mut result: Option<BracketMatch> = None;
20235
20236        for pair in buffer
20237            .all_bracket_ranges(range.clone())
20238            .filter(move |pair| {
20239                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20240            })
20241        {
20242            let len = pair.close_range.end - pair.open_range.start;
20243
20244            if let Some(existing) = &result {
20245                let existing_len = existing.close_range.end - existing.open_range.start;
20246                if len > existing_len {
20247                    continue;
20248                }
20249            }
20250
20251            result = Some(pair);
20252        }
20253
20254        result
20255    };
20256    let Some(pair) = pair else {
20257        return false;
20258    };
20259    pair.newline_only
20260        && buffer
20261            .chars_for_range(pair.open_range.end..range.start)
20262            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20263            .all(|c| c.is_whitespace() && c != '\n')
20264}
20265
20266fn update_uncommitted_diff_for_buffer(
20267    editor: Entity<Editor>,
20268    project: &Entity<Project>,
20269    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20270    buffer: Entity<MultiBuffer>,
20271    cx: &mut App,
20272) -> Task<()> {
20273    let mut tasks = Vec::new();
20274    project.update(cx, |project, cx| {
20275        for buffer in buffers {
20276            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20277                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20278            }
20279        }
20280    });
20281    cx.spawn(async move |cx| {
20282        let diffs = future::join_all(tasks).await;
20283        if editor
20284            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20285            .unwrap_or(false)
20286        {
20287            return;
20288        }
20289
20290        buffer
20291            .update(cx, |buffer, cx| {
20292                for diff in diffs.into_iter().flatten() {
20293                    buffer.add_diff(diff, cx);
20294                }
20295            })
20296            .ok();
20297    })
20298}
20299
20300fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20301    let tab_size = tab_size.get() as usize;
20302    let mut width = offset;
20303
20304    for ch in text.chars() {
20305        width += if ch == '\t' {
20306            tab_size - (width % tab_size)
20307        } else {
20308            1
20309        };
20310    }
20311
20312    width - offset
20313}
20314
20315#[cfg(test)]
20316mod tests {
20317    use super::*;
20318
20319    #[test]
20320    fn test_string_size_with_expanded_tabs() {
20321        let nz = |val| NonZeroU32::new(val).unwrap();
20322        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20323        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20324        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20325        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20326        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20327        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20328        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20329        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20330    }
20331}
20332
20333/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20334struct WordBreakingTokenizer<'a> {
20335    input: &'a str,
20336}
20337
20338impl<'a> WordBreakingTokenizer<'a> {
20339    fn new(input: &'a str) -> Self {
20340        Self { input }
20341    }
20342}
20343
20344fn is_char_ideographic(ch: char) -> bool {
20345    use unicode_script::Script::*;
20346    use unicode_script::UnicodeScript;
20347    matches!(ch.script(), Han | Tangut | Yi)
20348}
20349
20350fn is_grapheme_ideographic(text: &str) -> bool {
20351    text.chars().any(is_char_ideographic)
20352}
20353
20354fn is_grapheme_whitespace(text: &str) -> bool {
20355    text.chars().any(|x| x.is_whitespace())
20356}
20357
20358fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20359    text.chars().next().map_or(false, |ch| {
20360        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20361    })
20362}
20363
20364#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20365enum WordBreakToken<'a> {
20366    Word { token: &'a str, grapheme_len: usize },
20367    InlineWhitespace { token: &'a str, grapheme_len: usize },
20368    Newline,
20369}
20370
20371impl<'a> Iterator for WordBreakingTokenizer<'a> {
20372    /// Yields a span, the count of graphemes in the token, and whether it was
20373    /// whitespace. Note that it also breaks at word boundaries.
20374    type Item = WordBreakToken<'a>;
20375
20376    fn next(&mut self) -> Option<Self::Item> {
20377        use unicode_segmentation::UnicodeSegmentation;
20378        if self.input.is_empty() {
20379            return None;
20380        }
20381
20382        let mut iter = self.input.graphemes(true).peekable();
20383        let mut offset = 0;
20384        let mut grapheme_len = 0;
20385        if let Some(first_grapheme) = iter.next() {
20386            let is_newline = first_grapheme == "\n";
20387            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20388            offset += first_grapheme.len();
20389            grapheme_len += 1;
20390            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20391                if let Some(grapheme) = iter.peek().copied() {
20392                    if should_stay_with_preceding_ideograph(grapheme) {
20393                        offset += grapheme.len();
20394                        grapheme_len += 1;
20395                    }
20396                }
20397            } else {
20398                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20399                let mut next_word_bound = words.peek().copied();
20400                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20401                    next_word_bound = words.next();
20402                }
20403                while let Some(grapheme) = iter.peek().copied() {
20404                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20405                        break;
20406                    };
20407                    if is_grapheme_whitespace(grapheme) != is_whitespace
20408                        || (grapheme == "\n") != is_newline
20409                    {
20410                        break;
20411                    };
20412                    offset += grapheme.len();
20413                    grapheme_len += 1;
20414                    iter.next();
20415                }
20416            }
20417            let token = &self.input[..offset];
20418            self.input = &self.input[offset..];
20419            if token == "\n" {
20420                Some(WordBreakToken::Newline)
20421            } else if is_whitespace {
20422                Some(WordBreakToken::InlineWhitespace {
20423                    token,
20424                    grapheme_len,
20425                })
20426            } else {
20427                Some(WordBreakToken::Word {
20428                    token,
20429                    grapheme_len,
20430                })
20431            }
20432        } else {
20433            None
20434        }
20435    }
20436}
20437
20438#[test]
20439fn test_word_breaking_tokenizer() {
20440    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20441        ("", &[]),
20442        ("  ", &[whitespace("  ", 2)]),
20443        ("Ʒ", &[word("Ʒ", 1)]),
20444        ("Ǽ", &[word("Ǽ", 1)]),
20445        ("", &[word("", 1)]),
20446        ("⋑⋑", &[word("⋑⋑", 2)]),
20447        (
20448            "原理,进而",
20449            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20450        ),
20451        (
20452            "hello world",
20453            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20454        ),
20455        (
20456            "hello, world",
20457            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20458        ),
20459        (
20460            "  hello world",
20461            &[
20462                whitespace("  ", 2),
20463                word("hello", 5),
20464                whitespace(" ", 1),
20465                word("world", 5),
20466            ],
20467        ),
20468        (
20469            "这是什么 \n 钢笔",
20470            &[
20471                word("", 1),
20472                word("", 1),
20473                word("", 1),
20474                word("", 1),
20475                whitespace(" ", 1),
20476                newline(),
20477                whitespace(" ", 1),
20478                word("", 1),
20479                word("", 1),
20480            ],
20481        ),
20482        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20483    ];
20484
20485    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20486        WordBreakToken::Word {
20487            token,
20488            grapheme_len,
20489        }
20490    }
20491
20492    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20493        WordBreakToken::InlineWhitespace {
20494            token,
20495            grapheme_len,
20496        }
20497    }
20498
20499    fn newline() -> WordBreakToken<'static> {
20500        WordBreakToken::Newline
20501    }
20502
20503    for (input, result) in tests {
20504        assert_eq!(
20505            WordBreakingTokenizer::new(input)
20506                .collect::<Vec<_>>()
20507                .as_slice(),
20508            *result,
20509        );
20510    }
20511}
20512
20513fn wrap_with_prefix(
20514    line_prefix: String,
20515    unwrapped_text: String,
20516    wrap_column: usize,
20517    tab_size: NonZeroU32,
20518    preserve_existing_whitespace: bool,
20519) -> String {
20520    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20521    let mut wrapped_text = String::new();
20522    let mut current_line = line_prefix.clone();
20523
20524    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20525    let mut current_line_len = line_prefix_len;
20526    let mut in_whitespace = false;
20527    for token in tokenizer {
20528        let have_preceding_whitespace = in_whitespace;
20529        match token {
20530            WordBreakToken::Word {
20531                token,
20532                grapheme_len,
20533            } => {
20534                in_whitespace = false;
20535                if current_line_len + grapheme_len > wrap_column
20536                    && current_line_len != line_prefix_len
20537                {
20538                    wrapped_text.push_str(current_line.trim_end());
20539                    wrapped_text.push('\n');
20540                    current_line.truncate(line_prefix.len());
20541                    current_line_len = line_prefix_len;
20542                }
20543                current_line.push_str(token);
20544                current_line_len += grapheme_len;
20545            }
20546            WordBreakToken::InlineWhitespace {
20547                mut token,
20548                mut grapheme_len,
20549            } => {
20550                in_whitespace = true;
20551                if have_preceding_whitespace && !preserve_existing_whitespace {
20552                    continue;
20553                }
20554                if !preserve_existing_whitespace {
20555                    token = " ";
20556                    grapheme_len = 1;
20557                }
20558                if current_line_len + grapheme_len > wrap_column {
20559                    wrapped_text.push_str(current_line.trim_end());
20560                    wrapped_text.push('\n');
20561                    current_line.truncate(line_prefix.len());
20562                    current_line_len = line_prefix_len;
20563                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20564                    current_line.push_str(token);
20565                    current_line_len += grapheme_len;
20566                }
20567            }
20568            WordBreakToken::Newline => {
20569                in_whitespace = true;
20570                if preserve_existing_whitespace {
20571                    wrapped_text.push_str(current_line.trim_end());
20572                    wrapped_text.push('\n');
20573                    current_line.truncate(line_prefix.len());
20574                    current_line_len = line_prefix_len;
20575                } else if have_preceding_whitespace {
20576                    continue;
20577                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20578                {
20579                    wrapped_text.push_str(current_line.trim_end());
20580                    wrapped_text.push('\n');
20581                    current_line.truncate(line_prefix.len());
20582                    current_line_len = line_prefix_len;
20583                } else if current_line_len != line_prefix_len {
20584                    current_line.push(' ');
20585                    current_line_len += 1;
20586                }
20587            }
20588        }
20589    }
20590
20591    if !current_line.is_empty() {
20592        wrapped_text.push_str(&current_line);
20593    }
20594    wrapped_text
20595}
20596
20597#[test]
20598fn test_wrap_with_prefix() {
20599    assert_eq!(
20600        wrap_with_prefix(
20601            "# ".to_string(),
20602            "abcdefg".to_string(),
20603            4,
20604            NonZeroU32::new(4).unwrap(),
20605            false,
20606        ),
20607        "# abcdefg"
20608    );
20609    assert_eq!(
20610        wrap_with_prefix(
20611            "".to_string(),
20612            "\thello world".to_string(),
20613            8,
20614            NonZeroU32::new(4).unwrap(),
20615            false,
20616        ),
20617        "hello\nworld"
20618    );
20619    assert_eq!(
20620        wrap_with_prefix(
20621            "// ".to_string(),
20622            "xx \nyy zz aa bb cc".to_string(),
20623            12,
20624            NonZeroU32::new(4).unwrap(),
20625            false,
20626        ),
20627        "// xx yy zz\n// aa bb cc"
20628    );
20629    assert_eq!(
20630        wrap_with_prefix(
20631            String::new(),
20632            "这是什么 \n 钢笔".to_string(),
20633            3,
20634            NonZeroU32::new(4).unwrap(),
20635            false,
20636        ),
20637        "这是什\n么 钢\n"
20638    );
20639}
20640
20641pub trait CollaborationHub {
20642    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20643    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20644    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20645}
20646
20647impl CollaborationHub for Entity<Project> {
20648    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20649        self.read(cx).collaborators()
20650    }
20651
20652    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20653        self.read(cx).user_store().read(cx).participant_indices()
20654    }
20655
20656    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20657        let this = self.read(cx);
20658        let user_ids = this.collaborators().values().map(|c| c.user_id);
20659        this.user_store().read(cx).participant_names(user_ids, cx)
20660    }
20661}
20662
20663pub trait SemanticsProvider {
20664    fn hover(
20665        &self,
20666        buffer: &Entity<Buffer>,
20667        position: text::Anchor,
20668        cx: &mut App,
20669    ) -> Option<Task<Vec<project::Hover>>>;
20670
20671    fn inline_values(
20672        &self,
20673        buffer_handle: Entity<Buffer>,
20674        range: Range<text::Anchor>,
20675        cx: &mut App,
20676    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20677
20678    fn inlay_hints(
20679        &self,
20680        buffer_handle: Entity<Buffer>,
20681        range: Range<text::Anchor>,
20682        cx: &mut App,
20683    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20684
20685    fn resolve_inlay_hint(
20686        &self,
20687        hint: InlayHint,
20688        buffer_handle: Entity<Buffer>,
20689        server_id: LanguageServerId,
20690        cx: &mut App,
20691    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20692
20693    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20694
20695    fn document_highlights(
20696        &self,
20697        buffer: &Entity<Buffer>,
20698        position: text::Anchor,
20699        cx: &mut App,
20700    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20701
20702    fn definitions(
20703        &self,
20704        buffer: &Entity<Buffer>,
20705        position: text::Anchor,
20706        kind: GotoDefinitionKind,
20707        cx: &mut App,
20708    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20709
20710    fn range_for_rename(
20711        &self,
20712        buffer: &Entity<Buffer>,
20713        position: text::Anchor,
20714        cx: &mut App,
20715    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20716
20717    fn perform_rename(
20718        &self,
20719        buffer: &Entity<Buffer>,
20720        position: text::Anchor,
20721        new_name: String,
20722        cx: &mut App,
20723    ) -> Option<Task<Result<ProjectTransaction>>>;
20724
20725    fn pull_diagnostics_for_buffer(
20726        &self,
20727        buffer: Entity<Buffer>,
20728        cx: &mut App,
20729    ) -> Task<anyhow::Result<()>>;
20730}
20731
20732pub trait CompletionProvider {
20733    fn completions(
20734        &self,
20735        excerpt_id: ExcerptId,
20736        buffer: &Entity<Buffer>,
20737        buffer_position: text::Anchor,
20738        trigger: CompletionContext,
20739        window: &mut Window,
20740        cx: &mut Context<Editor>,
20741    ) -> Task<Result<Vec<CompletionResponse>>>;
20742
20743    fn resolve_completions(
20744        &self,
20745        _buffer: Entity<Buffer>,
20746        _completion_indices: Vec<usize>,
20747        _completions: Rc<RefCell<Box<[Completion]>>>,
20748        _cx: &mut Context<Editor>,
20749    ) -> Task<Result<bool>> {
20750        Task::ready(Ok(false))
20751    }
20752
20753    fn apply_additional_edits_for_completion(
20754        &self,
20755        _buffer: Entity<Buffer>,
20756        _completions: Rc<RefCell<Box<[Completion]>>>,
20757        _completion_index: usize,
20758        _push_to_history: bool,
20759        _cx: &mut Context<Editor>,
20760    ) -> Task<Result<Option<language::Transaction>>> {
20761        Task::ready(Ok(None))
20762    }
20763
20764    fn is_completion_trigger(
20765        &self,
20766        buffer: &Entity<Buffer>,
20767        position: language::Anchor,
20768        text: &str,
20769        trigger_in_words: bool,
20770        menu_is_open: bool,
20771        cx: &mut Context<Editor>,
20772    ) -> bool;
20773
20774    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20775
20776    fn sort_completions(&self) -> bool {
20777        true
20778    }
20779
20780    fn filter_completions(&self) -> bool {
20781        true
20782    }
20783}
20784
20785pub trait CodeActionProvider {
20786    fn id(&self) -> Arc<str>;
20787
20788    fn code_actions(
20789        &self,
20790        buffer: &Entity<Buffer>,
20791        range: Range<text::Anchor>,
20792        window: &mut Window,
20793        cx: &mut App,
20794    ) -> Task<Result<Vec<CodeAction>>>;
20795
20796    fn apply_code_action(
20797        &self,
20798        buffer_handle: Entity<Buffer>,
20799        action: CodeAction,
20800        excerpt_id: ExcerptId,
20801        push_to_history: bool,
20802        window: &mut Window,
20803        cx: &mut App,
20804    ) -> Task<Result<ProjectTransaction>>;
20805}
20806
20807impl CodeActionProvider for Entity<Project> {
20808    fn id(&self) -> Arc<str> {
20809        "project".into()
20810    }
20811
20812    fn code_actions(
20813        &self,
20814        buffer: &Entity<Buffer>,
20815        range: Range<text::Anchor>,
20816        _window: &mut Window,
20817        cx: &mut App,
20818    ) -> Task<Result<Vec<CodeAction>>> {
20819        self.update(cx, |project, cx| {
20820            let code_lens = project.code_lens(buffer, range.clone(), cx);
20821            let code_actions = project.code_actions(buffer, range, None, cx);
20822            cx.background_spawn(async move {
20823                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20824                Ok(code_lens
20825                    .context("code lens fetch")?
20826                    .into_iter()
20827                    .chain(code_actions.context("code action fetch")?)
20828                    .collect())
20829            })
20830        })
20831    }
20832
20833    fn apply_code_action(
20834        &self,
20835        buffer_handle: Entity<Buffer>,
20836        action: CodeAction,
20837        _excerpt_id: ExcerptId,
20838        push_to_history: bool,
20839        _window: &mut Window,
20840        cx: &mut App,
20841    ) -> Task<Result<ProjectTransaction>> {
20842        self.update(cx, |project, cx| {
20843            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20844        })
20845    }
20846}
20847
20848fn snippet_completions(
20849    project: &Project,
20850    buffer: &Entity<Buffer>,
20851    buffer_position: text::Anchor,
20852    cx: &mut App,
20853) -> Task<Result<CompletionResponse>> {
20854    let languages = buffer.read(cx).languages_at(buffer_position);
20855    let snippet_store = project.snippets().read(cx);
20856
20857    let scopes: Vec<_> = languages
20858        .iter()
20859        .filter_map(|language| {
20860            let language_name = language.lsp_id();
20861            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20862
20863            if snippets.is_empty() {
20864                None
20865            } else {
20866                Some((language.default_scope(), snippets))
20867            }
20868        })
20869        .collect();
20870
20871    if scopes.is_empty() {
20872        return Task::ready(Ok(CompletionResponse {
20873            completions: vec![],
20874            is_incomplete: false,
20875        }));
20876    }
20877
20878    let snapshot = buffer.read(cx).text_snapshot();
20879    let chars: String = snapshot
20880        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20881        .collect();
20882    let executor = cx.background_executor().clone();
20883
20884    cx.background_spawn(async move {
20885        let mut is_incomplete = false;
20886        let mut completions: Vec<Completion> = Vec::new();
20887        for (scope, snippets) in scopes.into_iter() {
20888            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20889            let mut last_word = chars
20890                .chars()
20891                .take_while(|c| classifier.is_word(*c))
20892                .collect::<String>();
20893            last_word = last_word.chars().rev().collect();
20894
20895            if last_word.is_empty() {
20896                return Ok(CompletionResponse {
20897                    completions: vec![],
20898                    is_incomplete: true,
20899                });
20900            }
20901
20902            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20903            let to_lsp = |point: &text::Anchor| {
20904                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20905                point_to_lsp(end)
20906            };
20907            let lsp_end = to_lsp(&buffer_position);
20908
20909            let candidates = snippets
20910                .iter()
20911                .enumerate()
20912                .flat_map(|(ix, snippet)| {
20913                    snippet
20914                        .prefix
20915                        .iter()
20916                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20917                })
20918                .collect::<Vec<StringMatchCandidate>>();
20919
20920            const MAX_RESULTS: usize = 100;
20921            let mut matches = fuzzy::match_strings(
20922                &candidates,
20923                &last_word,
20924                last_word.chars().any(|c| c.is_uppercase()),
20925                MAX_RESULTS,
20926                &Default::default(),
20927                executor.clone(),
20928            )
20929            .await;
20930
20931            if matches.len() >= MAX_RESULTS {
20932                is_incomplete = true;
20933            }
20934
20935            // Remove all candidates where the query's start does not match the start of any word in the candidate
20936            if let Some(query_start) = last_word.chars().next() {
20937                matches.retain(|string_match| {
20938                    split_words(&string_match.string).any(|word| {
20939                        // Check that the first codepoint of the word as lowercase matches the first
20940                        // codepoint of the query as lowercase
20941                        word.chars()
20942                            .flat_map(|codepoint| codepoint.to_lowercase())
20943                            .zip(query_start.to_lowercase())
20944                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20945                    })
20946                });
20947            }
20948
20949            let matched_strings = matches
20950                .into_iter()
20951                .map(|m| m.string)
20952                .collect::<HashSet<_>>();
20953
20954            completions.extend(snippets.iter().filter_map(|snippet| {
20955                let matching_prefix = snippet
20956                    .prefix
20957                    .iter()
20958                    .find(|prefix| matched_strings.contains(*prefix))?;
20959                let start = as_offset - last_word.len();
20960                let start = snapshot.anchor_before(start);
20961                let range = start..buffer_position;
20962                let lsp_start = to_lsp(&start);
20963                let lsp_range = lsp::Range {
20964                    start: lsp_start,
20965                    end: lsp_end,
20966                };
20967                Some(Completion {
20968                    replace_range: range,
20969                    new_text: snippet.body.clone(),
20970                    source: CompletionSource::Lsp {
20971                        insert_range: None,
20972                        server_id: LanguageServerId(usize::MAX),
20973                        resolved: true,
20974                        lsp_completion: Box::new(lsp::CompletionItem {
20975                            label: snippet.prefix.first().unwrap().clone(),
20976                            kind: Some(CompletionItemKind::SNIPPET),
20977                            label_details: snippet.description.as_ref().map(|description| {
20978                                lsp::CompletionItemLabelDetails {
20979                                    detail: Some(description.clone()),
20980                                    description: None,
20981                                }
20982                            }),
20983                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20984                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20985                                lsp::InsertReplaceEdit {
20986                                    new_text: snippet.body.clone(),
20987                                    insert: lsp_range,
20988                                    replace: lsp_range,
20989                                },
20990                            )),
20991                            filter_text: Some(snippet.body.clone()),
20992                            sort_text: Some(char::MAX.to_string()),
20993                            ..lsp::CompletionItem::default()
20994                        }),
20995                        lsp_defaults: None,
20996                    },
20997                    label: CodeLabel {
20998                        text: matching_prefix.clone(),
20999                        runs: Vec::new(),
21000                        filter_range: 0..matching_prefix.len(),
21001                    },
21002                    icon_path: None,
21003                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21004                        single_line: snippet.name.clone().into(),
21005                        plain_text: snippet
21006                            .description
21007                            .clone()
21008                            .map(|description| description.into()),
21009                    }),
21010                    insert_text_mode: None,
21011                    confirm: None,
21012                })
21013            }))
21014        }
21015
21016        Ok(CompletionResponse {
21017            completions,
21018            is_incomplete,
21019        })
21020    })
21021}
21022
21023impl CompletionProvider for Entity<Project> {
21024    fn completions(
21025        &self,
21026        _excerpt_id: ExcerptId,
21027        buffer: &Entity<Buffer>,
21028        buffer_position: text::Anchor,
21029        options: CompletionContext,
21030        _window: &mut Window,
21031        cx: &mut Context<Editor>,
21032    ) -> Task<Result<Vec<CompletionResponse>>> {
21033        self.update(cx, |project, cx| {
21034            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21035            let project_completions = project.completions(buffer, buffer_position, options, cx);
21036            cx.background_spawn(async move {
21037                let mut responses = project_completions.await?;
21038                let snippets = snippets.await?;
21039                if !snippets.completions.is_empty() {
21040                    responses.push(snippets);
21041                }
21042                Ok(responses)
21043            })
21044        })
21045    }
21046
21047    fn resolve_completions(
21048        &self,
21049        buffer: Entity<Buffer>,
21050        completion_indices: Vec<usize>,
21051        completions: Rc<RefCell<Box<[Completion]>>>,
21052        cx: &mut Context<Editor>,
21053    ) -> Task<Result<bool>> {
21054        self.update(cx, |project, cx| {
21055            project.lsp_store().update(cx, |lsp_store, cx| {
21056                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21057            })
21058        })
21059    }
21060
21061    fn apply_additional_edits_for_completion(
21062        &self,
21063        buffer: Entity<Buffer>,
21064        completions: Rc<RefCell<Box<[Completion]>>>,
21065        completion_index: usize,
21066        push_to_history: bool,
21067        cx: &mut Context<Editor>,
21068    ) -> Task<Result<Option<language::Transaction>>> {
21069        self.update(cx, |project, cx| {
21070            project.lsp_store().update(cx, |lsp_store, cx| {
21071                lsp_store.apply_additional_edits_for_completion(
21072                    buffer,
21073                    completions,
21074                    completion_index,
21075                    push_to_history,
21076                    cx,
21077                )
21078            })
21079        })
21080    }
21081
21082    fn is_completion_trigger(
21083        &self,
21084        buffer: &Entity<Buffer>,
21085        position: language::Anchor,
21086        text: &str,
21087        trigger_in_words: bool,
21088        menu_is_open: bool,
21089        cx: &mut Context<Editor>,
21090    ) -> bool {
21091        let mut chars = text.chars();
21092        let char = if let Some(char) = chars.next() {
21093            char
21094        } else {
21095            return false;
21096        };
21097        if chars.next().is_some() {
21098            return false;
21099        }
21100
21101        let buffer = buffer.read(cx);
21102        let snapshot = buffer.snapshot();
21103        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21104            return false;
21105        }
21106        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21107        if trigger_in_words && classifier.is_word(char) {
21108            return true;
21109        }
21110
21111        buffer.completion_triggers().contains(text)
21112    }
21113}
21114
21115impl SemanticsProvider for Entity<Project> {
21116    fn hover(
21117        &self,
21118        buffer: &Entity<Buffer>,
21119        position: text::Anchor,
21120        cx: &mut App,
21121    ) -> Option<Task<Vec<project::Hover>>> {
21122        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21123    }
21124
21125    fn document_highlights(
21126        &self,
21127        buffer: &Entity<Buffer>,
21128        position: text::Anchor,
21129        cx: &mut App,
21130    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21131        Some(self.update(cx, |project, cx| {
21132            project.document_highlights(buffer, position, cx)
21133        }))
21134    }
21135
21136    fn definitions(
21137        &self,
21138        buffer: &Entity<Buffer>,
21139        position: text::Anchor,
21140        kind: GotoDefinitionKind,
21141        cx: &mut App,
21142    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21143        Some(self.update(cx, |project, cx| match kind {
21144            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21145            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21146            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21147            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21148        }))
21149    }
21150
21151    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21152        // TODO: make this work for remote projects
21153        self.update(cx, |project, cx| {
21154            if project
21155                .active_debug_session(cx)
21156                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21157            {
21158                return true;
21159            }
21160
21161            buffer.update(cx, |buffer, cx| {
21162                project.any_language_server_supports_inlay_hints(buffer, cx)
21163            })
21164        })
21165    }
21166
21167    fn inline_values(
21168        &self,
21169        buffer_handle: Entity<Buffer>,
21170
21171        range: Range<text::Anchor>,
21172        cx: &mut App,
21173    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21174        self.update(cx, |project, cx| {
21175            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21176
21177            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21178        })
21179    }
21180
21181    fn inlay_hints(
21182        &self,
21183        buffer_handle: Entity<Buffer>,
21184        range: Range<text::Anchor>,
21185        cx: &mut App,
21186    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21187        Some(self.update(cx, |project, cx| {
21188            project.inlay_hints(buffer_handle, range, cx)
21189        }))
21190    }
21191
21192    fn resolve_inlay_hint(
21193        &self,
21194        hint: InlayHint,
21195        buffer_handle: Entity<Buffer>,
21196        server_id: LanguageServerId,
21197        cx: &mut App,
21198    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21199        Some(self.update(cx, |project, cx| {
21200            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21201        }))
21202    }
21203
21204    fn range_for_rename(
21205        &self,
21206        buffer: &Entity<Buffer>,
21207        position: text::Anchor,
21208        cx: &mut App,
21209    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21210        Some(self.update(cx, |project, cx| {
21211            let buffer = buffer.clone();
21212            let task = project.prepare_rename(buffer.clone(), position, cx);
21213            cx.spawn(async move |_, cx| {
21214                Ok(match task.await? {
21215                    PrepareRenameResponse::Success(range) => Some(range),
21216                    PrepareRenameResponse::InvalidPosition => None,
21217                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21218                        // Fallback on using TreeSitter info to determine identifier range
21219                        buffer.read_with(cx, |buffer, _| {
21220                            let snapshot = buffer.snapshot();
21221                            let (range, kind) = snapshot.surrounding_word(position);
21222                            if kind != Some(CharKind::Word) {
21223                                return None;
21224                            }
21225                            Some(
21226                                snapshot.anchor_before(range.start)
21227                                    ..snapshot.anchor_after(range.end),
21228                            )
21229                        })?
21230                    }
21231                })
21232            })
21233        }))
21234    }
21235
21236    fn perform_rename(
21237        &self,
21238        buffer: &Entity<Buffer>,
21239        position: text::Anchor,
21240        new_name: String,
21241        cx: &mut App,
21242    ) -> Option<Task<Result<ProjectTransaction>>> {
21243        Some(self.update(cx, |project, cx| {
21244            project.perform_rename(buffer.clone(), position, new_name, cx)
21245        }))
21246    }
21247
21248    fn pull_diagnostics_for_buffer(
21249        &self,
21250        buffer: Entity<Buffer>,
21251        cx: &mut App,
21252    ) -> Task<anyhow::Result<()>> {
21253        let diagnostics = self.update(cx, |project, cx| {
21254            project
21255                .lsp_store()
21256                .update(cx, |lsp_store, cx| lsp_store.pull_diagnostics(buffer, cx))
21257        });
21258        let project = self.clone();
21259        cx.spawn(async move |cx| {
21260            let diagnostics = diagnostics.await.context("pulling diagnostics")?;
21261            project.update(cx, |project, cx| {
21262                project.lsp_store().update(cx, |lsp_store, cx| {
21263                    for diagnostics_set in diagnostics {
21264                        let LspPullDiagnostics::Response {
21265                            server_id,
21266                            uri,
21267                            diagnostics,
21268                        } = diagnostics_set
21269                        else {
21270                            continue;
21271                        };
21272
21273                        let adapter = lsp_store.language_server_adapter_for_id(server_id);
21274                        let disk_based_sources = adapter
21275                            .as_ref()
21276                            .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
21277                            .unwrap_or(&[]);
21278                        match diagnostics {
21279                            PulledDiagnostics::Unchanged { result_id } => {
21280                                lsp_store
21281                                    .merge_diagnostics(
21282                                        server_id,
21283                                        lsp::PublishDiagnosticsParams {
21284                                            uri: uri.clone(),
21285                                            diagnostics: Vec::new(),
21286                                            version: None,
21287                                        },
21288                                        Some(result_id),
21289                                        DiagnosticSourceKind::Pulled,
21290                                        disk_based_sources,
21291                                        |_, _| true,
21292                                        cx,
21293                                    )
21294                                    .log_err();
21295                            }
21296                            PulledDiagnostics::Changed {
21297                                diagnostics,
21298                                result_id,
21299                            } => {
21300                                lsp_store
21301                                    .merge_diagnostics(
21302                                        server_id,
21303                                        lsp::PublishDiagnosticsParams {
21304                                            uri: uri.clone(),
21305                                            diagnostics,
21306                                            version: None,
21307                                        },
21308                                        result_id,
21309                                        DiagnosticSourceKind::Pulled,
21310                                        disk_based_sources,
21311                                        |old_diagnostic, _| match old_diagnostic.source_kind {
21312                                            DiagnosticSourceKind::Pulled => false,
21313                                            DiagnosticSourceKind::Other
21314                                            | DiagnosticSourceKind::Pushed => true,
21315                                        },
21316                                        cx,
21317                                    )
21318                                    .log_err();
21319                            }
21320                        }
21321                    }
21322                })
21323            })
21324        })
21325    }
21326}
21327
21328fn inlay_hint_settings(
21329    location: Anchor,
21330    snapshot: &MultiBufferSnapshot,
21331    cx: &mut Context<Editor>,
21332) -> InlayHintSettings {
21333    let file = snapshot.file_at(location);
21334    let language = snapshot.language_at(location).map(|l| l.name());
21335    language_settings(language, file, cx).inlay_hints
21336}
21337
21338fn consume_contiguous_rows(
21339    contiguous_row_selections: &mut Vec<Selection<Point>>,
21340    selection: &Selection<Point>,
21341    display_map: &DisplaySnapshot,
21342    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21343) -> (MultiBufferRow, MultiBufferRow) {
21344    contiguous_row_selections.push(selection.clone());
21345    let start_row = MultiBufferRow(selection.start.row);
21346    let mut end_row = ending_row(selection, display_map);
21347
21348    while let Some(next_selection) = selections.peek() {
21349        if next_selection.start.row <= end_row.0 {
21350            end_row = ending_row(next_selection, display_map);
21351            contiguous_row_selections.push(selections.next().unwrap().clone());
21352        } else {
21353            break;
21354        }
21355    }
21356    (start_row, end_row)
21357}
21358
21359fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21360    if next_selection.end.column > 0 || next_selection.is_empty() {
21361        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21362    } else {
21363        MultiBufferRow(next_selection.end.row)
21364    }
21365}
21366
21367impl EditorSnapshot {
21368    pub fn remote_selections_in_range<'a>(
21369        &'a self,
21370        range: &'a Range<Anchor>,
21371        collaboration_hub: &dyn CollaborationHub,
21372        cx: &'a App,
21373    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21374        let participant_names = collaboration_hub.user_names(cx);
21375        let participant_indices = collaboration_hub.user_participant_indices(cx);
21376        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21377        let collaborators_by_replica_id = collaborators_by_peer_id
21378            .values()
21379            .map(|collaborator| (collaborator.replica_id, collaborator))
21380            .collect::<HashMap<_, _>>();
21381        self.buffer_snapshot
21382            .selections_in_range(range, false)
21383            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21384                if replica_id == AGENT_REPLICA_ID {
21385                    Some(RemoteSelection {
21386                        replica_id,
21387                        selection,
21388                        cursor_shape,
21389                        line_mode,
21390                        collaborator_id: CollaboratorId::Agent,
21391                        user_name: Some("Agent".into()),
21392                        color: cx.theme().players().agent(),
21393                    })
21394                } else {
21395                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21396                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21397                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21398                    Some(RemoteSelection {
21399                        replica_id,
21400                        selection,
21401                        cursor_shape,
21402                        line_mode,
21403                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21404                        user_name,
21405                        color: if let Some(index) = participant_index {
21406                            cx.theme().players().color_for_participant(index.0)
21407                        } else {
21408                            cx.theme().players().absent()
21409                        },
21410                    })
21411                }
21412            })
21413    }
21414
21415    pub fn hunks_for_ranges(
21416        &self,
21417        ranges: impl IntoIterator<Item = Range<Point>>,
21418    ) -> Vec<MultiBufferDiffHunk> {
21419        let mut hunks = Vec::new();
21420        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21421            HashMap::default();
21422        for query_range in ranges {
21423            let query_rows =
21424                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21425            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21426                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21427            ) {
21428                // Include deleted hunks that are adjacent to the query range, because
21429                // otherwise they would be missed.
21430                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21431                if hunk.status().is_deleted() {
21432                    intersects_range |= hunk.row_range.start == query_rows.end;
21433                    intersects_range |= hunk.row_range.end == query_rows.start;
21434                }
21435                if intersects_range {
21436                    if !processed_buffer_rows
21437                        .entry(hunk.buffer_id)
21438                        .or_default()
21439                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21440                    {
21441                        continue;
21442                    }
21443                    hunks.push(hunk);
21444                }
21445            }
21446        }
21447
21448        hunks
21449    }
21450
21451    fn display_diff_hunks_for_rows<'a>(
21452        &'a self,
21453        display_rows: Range<DisplayRow>,
21454        folded_buffers: &'a HashSet<BufferId>,
21455    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21456        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21457        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21458
21459        self.buffer_snapshot
21460            .diff_hunks_in_range(buffer_start..buffer_end)
21461            .filter_map(|hunk| {
21462                if folded_buffers.contains(&hunk.buffer_id) {
21463                    return None;
21464                }
21465
21466                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21467                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21468
21469                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21470                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21471
21472                let display_hunk = if hunk_display_start.column() != 0 {
21473                    DisplayDiffHunk::Folded {
21474                        display_row: hunk_display_start.row(),
21475                    }
21476                } else {
21477                    let mut end_row = hunk_display_end.row();
21478                    if hunk_display_end.column() > 0 {
21479                        end_row.0 += 1;
21480                    }
21481                    let is_created_file = hunk.is_created_file();
21482                    DisplayDiffHunk::Unfolded {
21483                        status: hunk.status(),
21484                        diff_base_byte_range: hunk.diff_base_byte_range,
21485                        display_row_range: hunk_display_start.row()..end_row,
21486                        multi_buffer_range: Anchor::range_in_buffer(
21487                            hunk.excerpt_id,
21488                            hunk.buffer_id,
21489                            hunk.buffer_range,
21490                        ),
21491                        is_created_file,
21492                    }
21493                };
21494
21495                Some(display_hunk)
21496            })
21497    }
21498
21499    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21500        self.display_snapshot.buffer_snapshot.language_at(position)
21501    }
21502
21503    pub fn is_focused(&self) -> bool {
21504        self.is_focused
21505    }
21506
21507    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21508        self.placeholder_text.as_ref()
21509    }
21510
21511    pub fn scroll_position(&self) -> gpui::Point<f32> {
21512        self.scroll_anchor.scroll_position(&self.display_snapshot)
21513    }
21514
21515    fn gutter_dimensions(
21516        &self,
21517        font_id: FontId,
21518        font_size: Pixels,
21519        max_line_number_width: Pixels,
21520        cx: &App,
21521    ) -> Option<GutterDimensions> {
21522        if !self.show_gutter {
21523            return None;
21524        }
21525
21526        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21527        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21528
21529        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21530            matches!(
21531                ProjectSettings::get_global(cx).git.git_gutter,
21532                Some(GitGutterSetting::TrackedFiles)
21533            )
21534        });
21535        let gutter_settings = EditorSettings::get_global(cx).gutter;
21536        let show_line_numbers = self
21537            .show_line_numbers
21538            .unwrap_or(gutter_settings.line_numbers);
21539        let line_gutter_width = if show_line_numbers {
21540            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21541            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21542            max_line_number_width.max(min_width_for_number_on_gutter)
21543        } else {
21544            0.0.into()
21545        };
21546
21547        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21548        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21549
21550        let git_blame_entries_width =
21551            self.git_blame_gutter_max_author_length
21552                .map(|max_author_length| {
21553                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21554                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21555
21556                    /// The number of characters to dedicate to gaps and margins.
21557                    const SPACING_WIDTH: usize = 4;
21558
21559                    let max_char_count = max_author_length.min(renderer.max_author_length())
21560                        + ::git::SHORT_SHA_LENGTH
21561                        + MAX_RELATIVE_TIMESTAMP.len()
21562                        + SPACING_WIDTH;
21563
21564                    em_advance * max_char_count
21565                });
21566
21567        let is_singleton = self.buffer_snapshot.is_singleton();
21568
21569        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21570        left_padding += if !is_singleton {
21571            em_width * 4.0
21572        } else if show_runnables || show_breakpoints {
21573            em_width * 3.0
21574        } else if show_git_gutter && show_line_numbers {
21575            em_width * 2.0
21576        } else if show_git_gutter || show_line_numbers {
21577            em_width
21578        } else {
21579            px(0.)
21580        };
21581
21582        let shows_folds = is_singleton && gutter_settings.folds;
21583
21584        let right_padding = if shows_folds && show_line_numbers {
21585            em_width * 4.0
21586        } else if shows_folds || (!is_singleton && show_line_numbers) {
21587            em_width * 3.0
21588        } else if show_line_numbers {
21589            em_width
21590        } else {
21591            px(0.)
21592        };
21593
21594        Some(GutterDimensions {
21595            left_padding,
21596            right_padding,
21597            width: line_gutter_width + left_padding + right_padding,
21598            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21599            git_blame_entries_width,
21600        })
21601    }
21602
21603    pub fn render_crease_toggle(
21604        &self,
21605        buffer_row: MultiBufferRow,
21606        row_contains_cursor: bool,
21607        editor: Entity<Editor>,
21608        window: &mut Window,
21609        cx: &mut App,
21610    ) -> Option<AnyElement> {
21611        let folded = self.is_line_folded(buffer_row);
21612        let mut is_foldable = false;
21613
21614        if let Some(crease) = self
21615            .crease_snapshot
21616            .query_row(buffer_row, &self.buffer_snapshot)
21617        {
21618            is_foldable = true;
21619            match crease {
21620                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21621                    if let Some(render_toggle) = render_toggle {
21622                        let toggle_callback =
21623                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21624                                if folded {
21625                                    editor.update(cx, |editor, cx| {
21626                                        editor.fold_at(buffer_row, window, cx)
21627                                    });
21628                                } else {
21629                                    editor.update(cx, |editor, cx| {
21630                                        editor.unfold_at(buffer_row, window, cx)
21631                                    });
21632                                }
21633                            });
21634                        return Some((render_toggle)(
21635                            buffer_row,
21636                            folded,
21637                            toggle_callback,
21638                            window,
21639                            cx,
21640                        ));
21641                    }
21642                }
21643            }
21644        }
21645
21646        is_foldable |= self.starts_indent(buffer_row);
21647
21648        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21649            Some(
21650                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21651                    .toggle_state(folded)
21652                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21653                        if folded {
21654                            this.unfold_at(buffer_row, window, cx);
21655                        } else {
21656                            this.fold_at(buffer_row, window, cx);
21657                        }
21658                    }))
21659                    .into_any_element(),
21660            )
21661        } else {
21662            None
21663        }
21664    }
21665
21666    pub fn render_crease_trailer(
21667        &self,
21668        buffer_row: MultiBufferRow,
21669        window: &mut Window,
21670        cx: &mut App,
21671    ) -> Option<AnyElement> {
21672        let folded = self.is_line_folded(buffer_row);
21673        if let Crease::Inline { render_trailer, .. } = self
21674            .crease_snapshot
21675            .query_row(buffer_row, &self.buffer_snapshot)?
21676        {
21677            let render_trailer = render_trailer.as_ref()?;
21678            Some(render_trailer(buffer_row, folded, window, cx))
21679        } else {
21680            None
21681        }
21682    }
21683}
21684
21685impl Deref for EditorSnapshot {
21686    type Target = DisplaySnapshot;
21687
21688    fn deref(&self) -> &Self::Target {
21689        &self.display_snapshot
21690    }
21691}
21692
21693#[derive(Clone, Debug, PartialEq, Eq)]
21694pub enum EditorEvent {
21695    InputIgnored {
21696        text: Arc<str>,
21697    },
21698    InputHandled {
21699        utf16_range_to_replace: Option<Range<isize>>,
21700        text: Arc<str>,
21701    },
21702    ExcerptsAdded {
21703        buffer: Entity<Buffer>,
21704        predecessor: ExcerptId,
21705        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21706    },
21707    ExcerptsRemoved {
21708        ids: Vec<ExcerptId>,
21709        removed_buffer_ids: Vec<BufferId>,
21710    },
21711    BufferFoldToggled {
21712        ids: Vec<ExcerptId>,
21713        folded: bool,
21714    },
21715    ExcerptsEdited {
21716        ids: Vec<ExcerptId>,
21717    },
21718    ExcerptsExpanded {
21719        ids: Vec<ExcerptId>,
21720    },
21721    BufferEdited,
21722    Edited {
21723        transaction_id: clock::Lamport,
21724    },
21725    Reparsed(BufferId),
21726    Focused,
21727    FocusedIn,
21728    Blurred,
21729    DirtyChanged,
21730    Saved,
21731    TitleChanged,
21732    DiffBaseChanged,
21733    SelectionsChanged {
21734        local: bool,
21735    },
21736    ScrollPositionChanged {
21737        local: bool,
21738        autoscroll: bool,
21739    },
21740    Closed,
21741    TransactionUndone {
21742        transaction_id: clock::Lamport,
21743    },
21744    TransactionBegun {
21745        transaction_id: clock::Lamport,
21746    },
21747    Reloaded,
21748    CursorShapeChanged,
21749    PushedToNavHistory {
21750        anchor: Anchor,
21751        is_deactivate: bool,
21752    },
21753}
21754
21755impl EventEmitter<EditorEvent> for Editor {}
21756
21757impl Focusable for Editor {
21758    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21759        self.focus_handle.clone()
21760    }
21761}
21762
21763impl Render for Editor {
21764    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21765        let settings = ThemeSettings::get_global(cx);
21766
21767        let mut text_style = match self.mode {
21768            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21769                color: cx.theme().colors().editor_foreground,
21770                font_family: settings.ui_font.family.clone(),
21771                font_features: settings.ui_font.features.clone(),
21772                font_fallbacks: settings.ui_font.fallbacks.clone(),
21773                font_size: rems(0.875).into(),
21774                font_weight: settings.ui_font.weight,
21775                line_height: relative(settings.buffer_line_height.value()),
21776                ..Default::default()
21777            },
21778            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21779                color: cx.theme().colors().editor_foreground,
21780                font_family: settings.buffer_font.family.clone(),
21781                font_features: settings.buffer_font.features.clone(),
21782                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21783                font_size: settings.buffer_font_size(cx).into(),
21784                font_weight: settings.buffer_font.weight,
21785                line_height: relative(settings.buffer_line_height.value()),
21786                ..Default::default()
21787            },
21788        };
21789        if let Some(text_style_refinement) = &self.text_style_refinement {
21790            text_style.refine(text_style_refinement)
21791        }
21792
21793        let background = match self.mode {
21794            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21795            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21796            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21797            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21798        };
21799
21800        EditorElement::new(
21801            &cx.entity(),
21802            EditorStyle {
21803                background,
21804                local_player: cx.theme().players().local(),
21805                text: text_style,
21806                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21807                syntax: cx.theme().syntax().clone(),
21808                status: cx.theme().status().clone(),
21809                inlay_hints_style: make_inlay_hints_style(cx),
21810                inline_completion_styles: make_suggestion_styles(cx),
21811                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21812                show_underlines: !self.mode.is_minimap(),
21813            },
21814        )
21815    }
21816}
21817
21818impl EntityInputHandler for Editor {
21819    fn text_for_range(
21820        &mut self,
21821        range_utf16: Range<usize>,
21822        adjusted_range: &mut Option<Range<usize>>,
21823        _: &mut Window,
21824        cx: &mut Context<Self>,
21825    ) -> Option<String> {
21826        let snapshot = self.buffer.read(cx).read(cx);
21827        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21828        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21829        if (start.0..end.0) != range_utf16 {
21830            adjusted_range.replace(start.0..end.0);
21831        }
21832        Some(snapshot.text_for_range(start..end).collect())
21833    }
21834
21835    fn selected_text_range(
21836        &mut self,
21837        ignore_disabled_input: bool,
21838        _: &mut Window,
21839        cx: &mut Context<Self>,
21840    ) -> Option<UTF16Selection> {
21841        // Prevent the IME menu from appearing when holding down an alphabetic key
21842        // while input is disabled.
21843        if !ignore_disabled_input && !self.input_enabled {
21844            return None;
21845        }
21846
21847        let selection = self.selections.newest::<OffsetUtf16>(cx);
21848        let range = selection.range();
21849
21850        Some(UTF16Selection {
21851            range: range.start.0..range.end.0,
21852            reversed: selection.reversed,
21853        })
21854    }
21855
21856    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21857        let snapshot = self.buffer.read(cx).read(cx);
21858        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21859        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21860    }
21861
21862    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21863        self.clear_highlights::<InputComposition>(cx);
21864        self.ime_transaction.take();
21865    }
21866
21867    fn replace_text_in_range(
21868        &mut self,
21869        range_utf16: Option<Range<usize>>,
21870        text: &str,
21871        window: &mut Window,
21872        cx: &mut Context<Self>,
21873    ) {
21874        if !self.input_enabled {
21875            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21876            return;
21877        }
21878
21879        self.transact(window, cx, |this, window, cx| {
21880            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21881                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21882                Some(this.selection_replacement_ranges(range_utf16, cx))
21883            } else {
21884                this.marked_text_ranges(cx)
21885            };
21886
21887            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21888                let newest_selection_id = this.selections.newest_anchor().id;
21889                this.selections
21890                    .all::<OffsetUtf16>(cx)
21891                    .iter()
21892                    .zip(ranges_to_replace.iter())
21893                    .find_map(|(selection, range)| {
21894                        if selection.id == newest_selection_id {
21895                            Some(
21896                                (range.start.0 as isize - selection.head().0 as isize)
21897                                    ..(range.end.0 as isize - selection.head().0 as isize),
21898                            )
21899                        } else {
21900                            None
21901                        }
21902                    })
21903            });
21904
21905            cx.emit(EditorEvent::InputHandled {
21906                utf16_range_to_replace: range_to_replace,
21907                text: text.into(),
21908            });
21909
21910            if let Some(new_selected_ranges) = new_selected_ranges {
21911                this.change_selections(None, window, cx, |selections| {
21912                    selections.select_ranges(new_selected_ranges)
21913                });
21914                this.backspace(&Default::default(), window, cx);
21915            }
21916
21917            this.handle_input(text, window, cx);
21918        });
21919
21920        if let Some(transaction) = self.ime_transaction {
21921            self.buffer.update(cx, |buffer, cx| {
21922                buffer.group_until_transaction(transaction, cx);
21923            });
21924        }
21925
21926        self.unmark_text(window, cx);
21927    }
21928
21929    fn replace_and_mark_text_in_range(
21930        &mut self,
21931        range_utf16: Option<Range<usize>>,
21932        text: &str,
21933        new_selected_range_utf16: Option<Range<usize>>,
21934        window: &mut Window,
21935        cx: &mut Context<Self>,
21936    ) {
21937        if !self.input_enabled {
21938            return;
21939        }
21940
21941        let transaction = self.transact(window, cx, |this, window, cx| {
21942            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21943                let snapshot = this.buffer.read(cx).read(cx);
21944                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21945                    for marked_range in &mut marked_ranges {
21946                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21947                        marked_range.start.0 += relative_range_utf16.start;
21948                        marked_range.start =
21949                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21950                        marked_range.end =
21951                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21952                    }
21953                }
21954                Some(marked_ranges)
21955            } else if let Some(range_utf16) = range_utf16 {
21956                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21957                Some(this.selection_replacement_ranges(range_utf16, cx))
21958            } else {
21959                None
21960            };
21961
21962            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21963                let newest_selection_id = this.selections.newest_anchor().id;
21964                this.selections
21965                    .all::<OffsetUtf16>(cx)
21966                    .iter()
21967                    .zip(ranges_to_replace.iter())
21968                    .find_map(|(selection, range)| {
21969                        if selection.id == newest_selection_id {
21970                            Some(
21971                                (range.start.0 as isize - selection.head().0 as isize)
21972                                    ..(range.end.0 as isize - selection.head().0 as isize),
21973                            )
21974                        } else {
21975                            None
21976                        }
21977                    })
21978            });
21979
21980            cx.emit(EditorEvent::InputHandled {
21981                utf16_range_to_replace: range_to_replace,
21982                text: text.into(),
21983            });
21984
21985            if let Some(ranges) = ranges_to_replace {
21986                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21987            }
21988
21989            let marked_ranges = {
21990                let snapshot = this.buffer.read(cx).read(cx);
21991                this.selections
21992                    .disjoint_anchors()
21993                    .iter()
21994                    .map(|selection| {
21995                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21996                    })
21997                    .collect::<Vec<_>>()
21998            };
21999
22000            if text.is_empty() {
22001                this.unmark_text(window, cx);
22002            } else {
22003                this.highlight_text::<InputComposition>(
22004                    marked_ranges.clone(),
22005                    HighlightStyle {
22006                        underline: Some(UnderlineStyle {
22007                            thickness: px(1.),
22008                            color: None,
22009                            wavy: false,
22010                        }),
22011                        ..Default::default()
22012                    },
22013                    cx,
22014                );
22015            }
22016
22017            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22018            let use_autoclose = this.use_autoclose;
22019            let use_auto_surround = this.use_auto_surround;
22020            this.set_use_autoclose(false);
22021            this.set_use_auto_surround(false);
22022            this.handle_input(text, window, cx);
22023            this.set_use_autoclose(use_autoclose);
22024            this.set_use_auto_surround(use_auto_surround);
22025
22026            if let Some(new_selected_range) = new_selected_range_utf16 {
22027                let snapshot = this.buffer.read(cx).read(cx);
22028                let new_selected_ranges = marked_ranges
22029                    .into_iter()
22030                    .map(|marked_range| {
22031                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22032                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22033                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22034                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22035                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22036                    })
22037                    .collect::<Vec<_>>();
22038
22039                drop(snapshot);
22040                this.change_selections(None, window, cx, |selections| {
22041                    selections.select_ranges(new_selected_ranges)
22042                });
22043            }
22044        });
22045
22046        self.ime_transaction = self.ime_transaction.or(transaction);
22047        if let Some(transaction) = self.ime_transaction {
22048            self.buffer.update(cx, |buffer, cx| {
22049                buffer.group_until_transaction(transaction, cx);
22050            });
22051        }
22052
22053        if self.text_highlights::<InputComposition>(cx).is_none() {
22054            self.ime_transaction.take();
22055        }
22056    }
22057
22058    fn bounds_for_range(
22059        &mut self,
22060        range_utf16: Range<usize>,
22061        element_bounds: gpui::Bounds<Pixels>,
22062        window: &mut Window,
22063        cx: &mut Context<Self>,
22064    ) -> Option<gpui::Bounds<Pixels>> {
22065        let text_layout_details = self.text_layout_details(window);
22066        let gpui::Size {
22067            width: em_width,
22068            height: line_height,
22069        } = self.character_size(window);
22070
22071        let snapshot = self.snapshot(window, cx);
22072        let scroll_position = snapshot.scroll_position();
22073        let scroll_left = scroll_position.x * em_width;
22074
22075        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22076        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22077            + self.gutter_dimensions.width
22078            + self.gutter_dimensions.margin;
22079        let y = line_height * (start.row().as_f32() - scroll_position.y);
22080
22081        Some(Bounds {
22082            origin: element_bounds.origin + point(x, y),
22083            size: size(em_width, line_height),
22084        })
22085    }
22086
22087    fn character_index_for_point(
22088        &mut self,
22089        point: gpui::Point<Pixels>,
22090        _window: &mut Window,
22091        _cx: &mut Context<Self>,
22092    ) -> Option<usize> {
22093        let position_map = self.last_position_map.as_ref()?;
22094        if !position_map.text_hitbox.contains(&point) {
22095            return None;
22096        }
22097        let display_point = position_map.point_for_position(point).previous_valid;
22098        let anchor = position_map
22099            .snapshot
22100            .display_point_to_anchor(display_point, Bias::Left);
22101        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22102        Some(utf16_offset.0)
22103    }
22104}
22105
22106trait SelectionExt {
22107    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22108    fn spanned_rows(
22109        &self,
22110        include_end_if_at_line_start: bool,
22111        map: &DisplaySnapshot,
22112    ) -> Range<MultiBufferRow>;
22113}
22114
22115impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22116    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22117        let start = self
22118            .start
22119            .to_point(&map.buffer_snapshot)
22120            .to_display_point(map);
22121        let end = self
22122            .end
22123            .to_point(&map.buffer_snapshot)
22124            .to_display_point(map);
22125        if self.reversed {
22126            end..start
22127        } else {
22128            start..end
22129        }
22130    }
22131
22132    fn spanned_rows(
22133        &self,
22134        include_end_if_at_line_start: bool,
22135        map: &DisplaySnapshot,
22136    ) -> Range<MultiBufferRow> {
22137        let start = self.start.to_point(&map.buffer_snapshot);
22138        let mut end = self.end.to_point(&map.buffer_snapshot);
22139        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22140            end.row -= 1;
22141        }
22142
22143        let buffer_start = map.prev_line_boundary(start).0;
22144        let buffer_end = map.next_line_boundary(end).0;
22145        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22146    }
22147}
22148
22149impl<T: InvalidationRegion> InvalidationStack<T> {
22150    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22151    where
22152        S: Clone + ToOffset,
22153    {
22154        while let Some(region) = self.last() {
22155            let all_selections_inside_invalidation_ranges =
22156                if selections.len() == region.ranges().len() {
22157                    selections
22158                        .iter()
22159                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22160                        .all(|(selection, invalidation_range)| {
22161                            let head = selection.head().to_offset(buffer);
22162                            invalidation_range.start <= head && invalidation_range.end >= head
22163                        })
22164                } else {
22165                    false
22166                };
22167
22168            if all_selections_inside_invalidation_ranges {
22169                break;
22170            } else {
22171                self.pop();
22172            }
22173        }
22174    }
22175}
22176
22177impl<T> Default for InvalidationStack<T> {
22178    fn default() -> Self {
22179        Self(Default::default())
22180    }
22181}
22182
22183impl<T> Deref for InvalidationStack<T> {
22184    type Target = Vec<T>;
22185
22186    fn deref(&self) -> &Self::Target {
22187        &self.0
22188    }
22189}
22190
22191impl<T> DerefMut for InvalidationStack<T> {
22192    fn deref_mut(&mut self) -> &mut Self::Target {
22193        &mut self.0
22194    }
22195}
22196
22197impl InvalidationRegion for SnippetState {
22198    fn ranges(&self) -> &[Range<Anchor>] {
22199        &self.ranges[self.active_index]
22200    }
22201}
22202
22203fn inline_completion_edit_text(
22204    current_snapshot: &BufferSnapshot,
22205    edits: &[(Range<Anchor>, String)],
22206    edit_preview: &EditPreview,
22207    include_deletions: bool,
22208    cx: &App,
22209) -> HighlightedText {
22210    let edits = edits
22211        .iter()
22212        .map(|(anchor, text)| {
22213            (
22214                anchor.start.text_anchor..anchor.end.text_anchor,
22215                text.clone(),
22216            )
22217        })
22218        .collect::<Vec<_>>();
22219
22220    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22221}
22222
22223pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22224    match severity {
22225        lsp::DiagnosticSeverity::ERROR => colors.error,
22226        lsp::DiagnosticSeverity::WARNING => colors.warning,
22227        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22228        lsp::DiagnosticSeverity::HINT => colors.info,
22229        _ => colors.ignored,
22230    }
22231}
22232
22233pub fn styled_runs_for_code_label<'a>(
22234    label: &'a CodeLabel,
22235    syntax_theme: &'a theme::SyntaxTheme,
22236) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22237    let fade_out = HighlightStyle {
22238        fade_out: Some(0.35),
22239        ..Default::default()
22240    };
22241
22242    let mut prev_end = label.filter_range.end;
22243    label
22244        .runs
22245        .iter()
22246        .enumerate()
22247        .flat_map(move |(ix, (range, highlight_id))| {
22248            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22249                style
22250            } else {
22251                return Default::default();
22252            };
22253            let mut muted_style = style;
22254            muted_style.highlight(fade_out);
22255
22256            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22257            if range.start >= label.filter_range.end {
22258                if range.start > prev_end {
22259                    runs.push((prev_end..range.start, fade_out));
22260                }
22261                runs.push((range.clone(), muted_style));
22262            } else if range.end <= label.filter_range.end {
22263                runs.push((range.clone(), style));
22264            } else {
22265                runs.push((range.start..label.filter_range.end, style));
22266                runs.push((label.filter_range.end..range.end, muted_style));
22267            }
22268            prev_end = cmp::max(prev_end, range.end);
22269
22270            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22271                runs.push((prev_end..label.text.len(), fade_out));
22272            }
22273
22274            runs
22275        })
22276}
22277
22278pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22279    let mut prev_index = 0;
22280    let mut prev_codepoint: Option<char> = None;
22281    text.char_indices()
22282        .chain([(text.len(), '\0')])
22283        .filter_map(move |(index, codepoint)| {
22284            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22285            let is_boundary = index == text.len()
22286                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22287                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22288            if is_boundary {
22289                let chunk = &text[prev_index..index];
22290                prev_index = index;
22291                Some(chunk)
22292            } else {
22293                None
22294            }
22295        })
22296}
22297
22298pub trait RangeToAnchorExt: Sized {
22299    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22300
22301    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22302        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22303        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22304    }
22305}
22306
22307impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22308    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22309        let start_offset = self.start.to_offset(snapshot);
22310        let end_offset = self.end.to_offset(snapshot);
22311        if start_offset == end_offset {
22312            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22313        } else {
22314            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22315        }
22316    }
22317}
22318
22319pub trait RowExt {
22320    fn as_f32(&self) -> f32;
22321
22322    fn next_row(&self) -> Self;
22323
22324    fn previous_row(&self) -> Self;
22325
22326    fn minus(&self, other: Self) -> u32;
22327}
22328
22329impl RowExt for DisplayRow {
22330    fn as_f32(&self) -> f32 {
22331        self.0 as f32
22332    }
22333
22334    fn next_row(&self) -> Self {
22335        Self(self.0 + 1)
22336    }
22337
22338    fn previous_row(&self) -> Self {
22339        Self(self.0.saturating_sub(1))
22340    }
22341
22342    fn minus(&self, other: Self) -> u32 {
22343        self.0 - other.0
22344    }
22345}
22346
22347impl RowExt for MultiBufferRow {
22348    fn as_f32(&self) -> f32 {
22349        self.0 as f32
22350    }
22351
22352    fn next_row(&self) -> Self {
22353        Self(self.0 + 1)
22354    }
22355
22356    fn previous_row(&self) -> Self {
22357        Self(self.0.saturating_sub(1))
22358    }
22359
22360    fn minus(&self, other: Self) -> u32 {
22361        self.0 - other.0
22362    }
22363}
22364
22365trait RowRangeExt {
22366    type Row;
22367
22368    fn len(&self) -> usize;
22369
22370    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22371}
22372
22373impl RowRangeExt for Range<MultiBufferRow> {
22374    type Row = MultiBufferRow;
22375
22376    fn len(&self) -> usize {
22377        (self.end.0 - self.start.0) as usize
22378    }
22379
22380    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22381        (self.start.0..self.end.0).map(MultiBufferRow)
22382    }
22383}
22384
22385impl RowRangeExt for Range<DisplayRow> {
22386    type Row = DisplayRow;
22387
22388    fn len(&self) -> usize {
22389        (self.end.0 - self.start.0) as usize
22390    }
22391
22392    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22393        (self.start.0..self.end.0).map(DisplayRow)
22394    }
22395}
22396
22397/// If select range has more than one line, we
22398/// just point the cursor to range.start.
22399fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22400    if range.start.row == range.end.row {
22401        range
22402    } else {
22403        range.start..range.start
22404    }
22405}
22406pub struct KillRing(ClipboardItem);
22407impl Global for KillRing {}
22408
22409const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22410
22411enum BreakpointPromptEditAction {
22412    Log,
22413    Condition,
22414    HitCondition,
22415}
22416
22417struct BreakpointPromptEditor {
22418    pub(crate) prompt: Entity<Editor>,
22419    editor: WeakEntity<Editor>,
22420    breakpoint_anchor: Anchor,
22421    breakpoint: Breakpoint,
22422    edit_action: BreakpointPromptEditAction,
22423    block_ids: HashSet<CustomBlockId>,
22424    editor_margins: Arc<Mutex<EditorMargins>>,
22425    _subscriptions: Vec<Subscription>,
22426}
22427
22428impl BreakpointPromptEditor {
22429    const MAX_LINES: u8 = 4;
22430
22431    fn new(
22432        editor: WeakEntity<Editor>,
22433        breakpoint_anchor: Anchor,
22434        breakpoint: Breakpoint,
22435        edit_action: BreakpointPromptEditAction,
22436        window: &mut Window,
22437        cx: &mut Context<Self>,
22438    ) -> Self {
22439        let base_text = match edit_action {
22440            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22441            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22442            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22443        }
22444        .map(|msg| msg.to_string())
22445        .unwrap_or_default();
22446
22447        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22449
22450        let prompt = cx.new(|cx| {
22451            let mut prompt = Editor::new(
22452                EditorMode::AutoHeight {
22453                    max_lines: Self::MAX_LINES as usize,
22454                },
22455                buffer,
22456                None,
22457                window,
22458                cx,
22459            );
22460            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22461            prompt.set_show_cursor_when_unfocused(false, cx);
22462            prompt.set_placeholder_text(
22463                match edit_action {
22464                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22465                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22466                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22467                },
22468                cx,
22469            );
22470
22471            prompt
22472        });
22473
22474        Self {
22475            prompt,
22476            editor,
22477            breakpoint_anchor,
22478            breakpoint,
22479            edit_action,
22480            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22481            block_ids: Default::default(),
22482            _subscriptions: vec![],
22483        }
22484    }
22485
22486    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22487        self.block_ids.extend(block_ids)
22488    }
22489
22490    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22491        if let Some(editor) = self.editor.upgrade() {
22492            let message = self
22493                .prompt
22494                .read(cx)
22495                .buffer
22496                .read(cx)
22497                .as_singleton()
22498                .expect("A multi buffer in breakpoint prompt isn't possible")
22499                .read(cx)
22500                .as_rope()
22501                .to_string();
22502
22503            editor.update(cx, |editor, cx| {
22504                editor.edit_breakpoint_at_anchor(
22505                    self.breakpoint_anchor,
22506                    self.breakpoint.clone(),
22507                    match self.edit_action {
22508                        BreakpointPromptEditAction::Log => {
22509                            BreakpointEditAction::EditLogMessage(message.into())
22510                        }
22511                        BreakpointPromptEditAction::Condition => {
22512                            BreakpointEditAction::EditCondition(message.into())
22513                        }
22514                        BreakpointPromptEditAction::HitCondition => {
22515                            BreakpointEditAction::EditHitCondition(message.into())
22516                        }
22517                    },
22518                    cx,
22519                );
22520
22521                editor.remove_blocks(self.block_ids.clone(), None, cx);
22522                cx.focus_self(window);
22523            });
22524        }
22525    }
22526
22527    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22528        self.editor
22529            .update(cx, |editor, cx| {
22530                editor.remove_blocks(self.block_ids.clone(), None, cx);
22531                window.focus(&editor.focus_handle);
22532            })
22533            .log_err();
22534    }
22535
22536    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22537        let settings = ThemeSettings::get_global(cx);
22538        let text_style = TextStyle {
22539            color: if self.prompt.read(cx).read_only(cx) {
22540                cx.theme().colors().text_disabled
22541            } else {
22542                cx.theme().colors().text
22543            },
22544            font_family: settings.buffer_font.family.clone(),
22545            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22546            font_size: settings.buffer_font_size(cx).into(),
22547            font_weight: settings.buffer_font.weight,
22548            line_height: relative(settings.buffer_line_height.value()),
22549            ..Default::default()
22550        };
22551        EditorElement::new(
22552            &self.prompt,
22553            EditorStyle {
22554                background: cx.theme().colors().editor_background,
22555                local_player: cx.theme().players().local(),
22556                text: text_style,
22557                ..Default::default()
22558            },
22559        )
22560    }
22561}
22562
22563impl Render for BreakpointPromptEditor {
22564    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22565        let editor_margins = *self.editor_margins.lock();
22566        let gutter_dimensions = editor_margins.gutter;
22567        h_flex()
22568            .key_context("Editor")
22569            .bg(cx.theme().colors().editor_background)
22570            .border_y_1()
22571            .border_color(cx.theme().status().info_border)
22572            .size_full()
22573            .py(window.line_height() / 2.5)
22574            .on_action(cx.listener(Self::confirm))
22575            .on_action(cx.listener(Self::cancel))
22576            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22577            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22578    }
22579}
22580
22581impl Focusable for BreakpointPromptEditor {
22582    fn focus_handle(&self, cx: &App) -> FocusHandle {
22583        self.prompt.focus_handle(cx)
22584    }
22585}
22586
22587fn all_edits_insertions_or_deletions(
22588    edits: &Vec<(Range<Anchor>, String)>,
22589    snapshot: &MultiBufferSnapshot,
22590) -> bool {
22591    let mut all_insertions = true;
22592    let mut all_deletions = true;
22593
22594    for (range, new_text) in edits.iter() {
22595        let range_is_empty = range.to_offset(&snapshot).is_empty();
22596        let text_is_empty = new_text.is_empty();
22597
22598        if range_is_empty != text_is_empty {
22599            if range_is_empty {
22600                all_deletions = false;
22601            } else {
22602                all_insertions = false;
22603            }
22604        } else {
22605            return false;
22606        }
22607
22608        if !all_insertions && !all_deletions {
22609            return false;
22610        }
22611    }
22612    all_insertions || all_deletions
22613}
22614
22615struct MissingEditPredictionKeybindingTooltip;
22616
22617impl Render for MissingEditPredictionKeybindingTooltip {
22618    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22619        ui::tooltip_container(window, cx, |container, _, cx| {
22620            container
22621                .flex_shrink_0()
22622                .max_w_80()
22623                .min_h(rems_from_px(124.))
22624                .justify_between()
22625                .child(
22626                    v_flex()
22627                        .flex_1()
22628                        .text_ui_sm(cx)
22629                        .child(Label::new("Conflict with Accept Keybinding"))
22630                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22631                )
22632                .child(
22633                    h_flex()
22634                        .pb_1()
22635                        .gap_1()
22636                        .items_end()
22637                        .w_full()
22638                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22639                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22640                        }))
22641                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22642                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22643                        })),
22644                )
22645        })
22646    }
22647}
22648
22649#[derive(Debug, Clone, Copy, PartialEq)]
22650pub struct LineHighlight {
22651    pub background: Background,
22652    pub border: Option<gpui::Hsla>,
22653    pub include_gutter: bool,
22654    pub type_id: Option<TypeId>,
22655}
22656
22657fn render_diff_hunk_controls(
22658    row: u32,
22659    status: &DiffHunkStatus,
22660    hunk_range: Range<Anchor>,
22661    is_created_file: bool,
22662    line_height: Pixels,
22663    editor: &Entity<Editor>,
22664    _window: &mut Window,
22665    cx: &mut App,
22666) -> AnyElement {
22667    h_flex()
22668        .h(line_height)
22669        .mr_1()
22670        .gap_1()
22671        .px_0p5()
22672        .pb_1()
22673        .border_x_1()
22674        .border_b_1()
22675        .border_color(cx.theme().colors().border_variant)
22676        .rounded_b_lg()
22677        .bg(cx.theme().colors().editor_background)
22678        .gap_1()
22679        .block_mouse_except_scroll()
22680        .shadow_md()
22681        .child(if status.has_secondary_hunk() {
22682            Button::new(("stage", row as u64), "Stage")
22683                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22684                .tooltip({
22685                    let focus_handle = editor.focus_handle(cx);
22686                    move |window, cx| {
22687                        Tooltip::for_action_in(
22688                            "Stage Hunk",
22689                            &::git::ToggleStaged,
22690                            &focus_handle,
22691                            window,
22692                            cx,
22693                        )
22694                    }
22695                })
22696                .on_click({
22697                    let editor = editor.clone();
22698                    move |_event, _window, cx| {
22699                        editor.update(cx, |editor, cx| {
22700                            editor.stage_or_unstage_diff_hunks(
22701                                true,
22702                                vec![hunk_range.start..hunk_range.start],
22703                                cx,
22704                            );
22705                        });
22706                    }
22707                })
22708        } else {
22709            Button::new(("unstage", row as u64), "Unstage")
22710                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22711                .tooltip({
22712                    let focus_handle = editor.focus_handle(cx);
22713                    move |window, cx| {
22714                        Tooltip::for_action_in(
22715                            "Unstage Hunk",
22716                            &::git::ToggleStaged,
22717                            &focus_handle,
22718                            window,
22719                            cx,
22720                        )
22721                    }
22722                })
22723                .on_click({
22724                    let editor = editor.clone();
22725                    move |_event, _window, cx| {
22726                        editor.update(cx, |editor, cx| {
22727                            editor.stage_or_unstage_diff_hunks(
22728                                false,
22729                                vec![hunk_range.start..hunk_range.start],
22730                                cx,
22731                            );
22732                        });
22733                    }
22734                })
22735        })
22736        .child(
22737            Button::new(("restore", row as u64), "Restore")
22738                .tooltip({
22739                    let focus_handle = editor.focus_handle(cx);
22740                    move |window, cx| {
22741                        Tooltip::for_action_in(
22742                            "Restore Hunk",
22743                            &::git::Restore,
22744                            &focus_handle,
22745                            window,
22746                            cx,
22747                        )
22748                    }
22749                })
22750                .on_click({
22751                    let editor = editor.clone();
22752                    move |_event, window, cx| {
22753                        editor.update(cx, |editor, cx| {
22754                            let snapshot = editor.snapshot(window, cx);
22755                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22756                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22757                        });
22758                    }
22759                })
22760                .disabled(is_created_file),
22761        )
22762        .when(
22763            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22764            |el| {
22765                el.child(
22766                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22767                        .shape(IconButtonShape::Square)
22768                        .icon_size(IconSize::Small)
22769                        // .disabled(!has_multiple_hunks)
22770                        .tooltip({
22771                            let focus_handle = editor.focus_handle(cx);
22772                            move |window, cx| {
22773                                Tooltip::for_action_in(
22774                                    "Next Hunk",
22775                                    &GoToHunk,
22776                                    &focus_handle,
22777                                    window,
22778                                    cx,
22779                                )
22780                            }
22781                        })
22782                        .on_click({
22783                            let editor = editor.clone();
22784                            move |_event, window, cx| {
22785                                editor.update(cx, |editor, cx| {
22786                                    let snapshot = editor.snapshot(window, cx);
22787                                    let position =
22788                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22789                                    editor.go_to_hunk_before_or_after_position(
22790                                        &snapshot,
22791                                        position,
22792                                        Direction::Next,
22793                                        window,
22794                                        cx,
22795                                    );
22796                                    editor.expand_selected_diff_hunks(cx);
22797                                });
22798                            }
22799                        }),
22800                )
22801                .child(
22802                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22803                        .shape(IconButtonShape::Square)
22804                        .icon_size(IconSize::Small)
22805                        // .disabled(!has_multiple_hunks)
22806                        .tooltip({
22807                            let focus_handle = editor.focus_handle(cx);
22808                            move |window, cx| {
22809                                Tooltip::for_action_in(
22810                                    "Previous Hunk",
22811                                    &GoToPreviousHunk,
22812                                    &focus_handle,
22813                                    window,
22814                                    cx,
22815                                )
22816                            }
22817                        })
22818                        .on_click({
22819                            let editor = editor.clone();
22820                            move |_event, window, cx| {
22821                                editor.update(cx, |editor, cx| {
22822                                    let snapshot = editor.snapshot(window, cx);
22823                                    let point =
22824                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22825                                    editor.go_to_hunk_before_or_after_position(
22826                                        &snapshot,
22827                                        point,
22828                                        Direction::Prev,
22829                                        window,
22830                                        cx,
22831                                    );
22832                                    editor.expand_selected_diff_hunks(cx);
22833                                });
22834                            }
22835                        }),
22836                )
22837            },
22838        )
22839        .into_any_element()
22840}