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;
   18mod 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, SearchSettings,
   67    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,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::StringMatchCandidate;
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use smallvec::smallvec;
  142use std::{cell::OnceCell, iter::Peekable, ops::Not};
  143use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  144
  145pub use lsp::CompletionContext;
  146use lsp::{
  147    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  148    LanguageServerId, LanguageServerName,
  149};
  150
  151use language::BufferSnapshot;
  152pub use lsp_ext::lsp_tasks;
  153use movement::TextLayoutDetails;
  154pub use multi_buffer::{
  155    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  156    RowInfo, ToOffset, ToPoint,
  157};
  158use multi_buffer::{
  159    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  160    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  161};
  162use parking_lot::Mutex;
  163use project::{
  164    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  165    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  166    TaskSourceKind,
  167    debugger::breakpoint_store::Breakpoint,
  168    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  169    project_settings::{GitGutterSetting, ProjectSettings},
  170};
  171use rand::prelude::*;
  172use rpc::{ErrorExt, proto::*};
  173use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  174use selections_collection::{
  175    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  176};
  177use serde::{Deserialize, Serialize};
  178use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  179use smallvec::SmallVec;
  180use snippet::Snippet;
  181use std::sync::Arc;
  182use std::{
  183    any::TypeId,
  184    borrow::Cow,
  185    cell::RefCell,
  186    cmp::{self, Ordering, Reverse},
  187    mem,
  188    num::NonZeroU32,
  189    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  190    path::{Path, PathBuf},
  191    rc::Rc,
  192    time::{Duration, Instant},
  193};
  194pub use sum_tree::Bias;
  195use sum_tree::TreeMap;
  196use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  197use theme::{
  198    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  199    observe_buffer_font_size_adjustment,
  200};
  201use ui::{
  202    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  203    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  204};
  205use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemHandle, PreviewTabsSettings},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::hover_links::{find_url, find_url_from_range};
  216use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  217
  218pub const FILE_HEADER_HEIGHT: u32 = 2;
  219pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  220pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233
  234pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  235pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  236pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  253    alt: true,
  254    shift: true,
  255    control: false,
  256    platform: false,
  257    function: false,
  258};
  259
  260struct InlineValueCache {
  261    enabled: bool,
  262    inlays: Vec<InlayId>,
  263    refresh_task: Task<Option<()>>,
  264}
  265
  266impl InlineValueCache {
  267    fn new(enabled: bool) -> Self {
  268        Self {
  269            enabled,
  270            inlays: Vec::new(),
  271            refresh_task: Task::ready(None),
  272        }
  273    }
  274}
  275
  276#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  277pub enum InlayId {
  278    InlineCompletion(usize),
  279    Hint(usize),
  280    DebuggerValue(usize),
  281}
  282
  283impl InlayId {
  284    fn id(&self) -> usize {
  285        match self {
  286            Self::InlineCompletion(id) => *id,
  287            Self::Hint(id) => *id,
  288            Self::DebuggerValue(id) => *id,
  289        }
  290    }
  291}
  292
  293pub enum ActiveDebugLine {}
  294pub enum DebugStackFrameLine {}
  295enum DocumentHighlightRead {}
  296enum DocumentHighlightWrite {}
  297enum InputComposition {}
  298enum SelectedTextHighlight {}
  299
  300pub enum ConflictsOuter {}
  301pub enum ConflictsOurs {}
  302pub enum ConflictsTheirs {}
  303pub enum ConflictsOursMarker {}
  304pub enum ConflictsTheirsMarker {}
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329    },
  330}
  331
  332pub enum HideMouseCursorOrigin {
  333    TypingAction,
  334    MovementAction,
  335}
  336
  337pub fn init_settings(cx: &mut App) {
  338    EditorSettings::register(cx);
  339}
  340
  341pub fn init(cx: &mut App) {
  342    init_settings(cx);
  343
  344    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  345
  346    workspace::register_project_item::<Editor>(cx);
  347    workspace::FollowableViewRegistry::register::<Editor>(cx);
  348    workspace::register_serializable_item::<Editor>(cx);
  349
  350    cx.observe_new(
  351        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  352            workspace.register_action(Editor::new_file);
  353            workspace.register_action(Editor::new_file_vertical);
  354            workspace.register_action(Editor::new_file_horizontal);
  355            workspace.register_action(Editor::cancel_language_server_work);
  356        },
  357    )
  358    .detach();
  359
  360    cx.on_action(move |_: &workspace::NewFile, cx| {
  361        let app_state = workspace::AppState::global(cx);
  362        if let Some(app_state) = app_state.upgrade() {
  363            workspace::open_new(
  364                Default::default(),
  365                app_state,
  366                cx,
  367                |workspace, window, cx| {
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374    cx.on_action(move |_: &workspace::NewWindow, cx| {
  375        let app_state = workspace::AppState::global(cx);
  376        if let Some(app_state) = app_state.upgrade() {
  377            workspace::open_new(
  378                Default::default(),
  379                app_state,
  380                cx,
  381                |workspace, window, cx| {
  382                    cx.activate(true);
  383                    Editor::new_file(workspace, &Default::default(), window, cx)
  384                },
  385            )
  386            .detach();
  387        }
  388    });
  389}
  390
  391pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  392    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  393}
  394
  395pub trait DiagnosticRenderer {
  396    fn render_group(
  397        &self,
  398        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  399        buffer_id: BufferId,
  400        snapshot: EditorSnapshot,
  401        editor: WeakEntity<Editor>,
  402        cx: &mut App,
  403    ) -> Vec<BlockProperties<Anchor>>;
  404
  405    fn render_hover(
  406        &self,
  407        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  408        range: Range<Point>,
  409        buffer_id: BufferId,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        goal_column: u32,
  452    },
  453    Extend {
  454        position: DisplayPoint,
  455        click_count: usize,
  456    },
  457    Update {
  458        position: DisplayPoint,
  459        goal_column: u32,
  460        scroll_delta: gpui::Point<f32>,
  461    },
  462    End,
  463}
  464
  465#[derive(Clone, Debug)]
  466pub enum SelectMode {
  467    Character,
  468    Word(Range<Anchor>),
  469    Line(Range<Anchor>),
  470    All,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine {
  476        auto_width: bool,
  477    },
  478    AutoHeight {
  479        max_lines: usize,
  480    },
  481    Full {
  482        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  483        scale_ui_elements_with_buffer_font_size: bool,
  484        /// When set to `true`, the editor will render a background for the active line.
  485        show_active_line_background: bool,
  486        /// When set to `true`, the editor's height will be determined by its content.
  487        sized_by_content: bool,
  488    },
  489    Minimap {
  490        parent: WeakEntity<Editor>,
  491    },
  492}
  493
  494impl EditorMode {
  495    pub fn full() -> Self {
  496        Self::Full {
  497            scale_ui_elements_with_buffer_font_size: true,
  498            show_active_line_background: true,
  499            sized_by_content: false,
  500        }
  501    }
  502
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    fn is_minimap(&self) -> bool {
  508        matches!(self, Self::Minimap { .. })
  509    }
  510}
  511
  512#[derive(Copy, Clone, Debug)]
  513pub enum SoftWrap {
  514    /// Prefer not to wrap at all.
  515    ///
  516    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  517    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  518    GitDiff,
  519    /// Prefer a single line generally, unless an overly long line is encountered.
  520    None,
  521    /// Soft wrap lines that exceed the editor width.
  522    EditorWidth,
  523    /// Soft wrap lines at the preferred line length.
  524    Column(u32),
  525    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  526    Bounded(u32),
  527}
  528
  529#[derive(Clone)]
  530pub struct EditorStyle {
  531    pub background: Hsla,
  532    pub local_player: PlayerColor,
  533    pub text: TextStyle,
  534    pub scrollbar_width: Pixels,
  535    pub syntax: Arc<SyntaxTheme>,
  536    pub status: StatusColors,
  537    pub inlay_hints_style: HighlightStyle,
  538    pub inline_completion_styles: InlineCompletionStyles,
  539    pub unnecessary_code_fade: f32,
  540    pub show_underlines: bool,
  541}
  542
  543impl Default for EditorStyle {
  544    fn default() -> Self {
  545        Self {
  546            background: Hsla::default(),
  547            local_player: PlayerColor::default(),
  548            text: TextStyle::default(),
  549            scrollbar_width: Pixels::default(),
  550            syntax: Default::default(),
  551            // HACK: Status colors don't have a real default.
  552            // We should look into removing the status colors from the editor
  553            // style and retrieve them directly from the theme.
  554            status: StatusColors::dark(),
  555            inlay_hints_style: HighlightStyle::default(),
  556            inline_completion_styles: InlineCompletionStyles {
  557                insertion: HighlightStyle::default(),
  558                whitespace: HighlightStyle::default(),
  559            },
  560            unnecessary_code_fade: Default::default(),
  561            show_underlines: true,
  562        }
  563    }
  564}
  565
  566pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  567    let show_background = language_settings::language_settings(None, None, cx)
  568        .inlay_hints
  569        .show_background;
  570
  571    HighlightStyle {
  572        color: Some(cx.theme().status().hint),
  573        background_color: show_background.then(|| cx.theme().status().hint_background),
  574        ..HighlightStyle::default()
  575    }
  576}
  577
  578pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  579    InlineCompletionStyles {
  580        insertion: HighlightStyle {
  581            color: Some(cx.theme().status().predictive),
  582            ..HighlightStyle::default()
  583        },
  584        whitespace: HighlightStyle {
  585            background_color: Some(cx.theme().status().created_background),
  586            ..HighlightStyle::default()
  587        },
  588    }
  589}
  590
  591type CompletionId = usize;
  592
  593pub(crate) enum EditDisplayMode {
  594    TabAccept,
  595    DiffPopover,
  596    Inline,
  597}
  598
  599enum InlineCompletion {
  600    Edit {
  601        edits: Vec<(Range<Anchor>, String)>,
  602        edit_preview: Option<EditPreview>,
  603        display_mode: EditDisplayMode,
  604        snapshot: BufferSnapshot,
  605    },
  606    Move {
  607        target: Anchor,
  608        snapshot: BufferSnapshot,
  609    },
  610}
  611
  612struct InlineCompletionState {
  613    inlay_ids: Vec<InlayId>,
  614    completion: InlineCompletion,
  615    completion_id: Option<SharedString>,
  616    invalidation_range: Range<Anchor>,
  617}
  618
  619enum EditPredictionSettings {
  620    Disabled,
  621    Enabled {
  622        show_in_menu: bool,
  623        preview_requires_modifier: bool,
  624    },
  625}
  626
  627enum InlineCompletionHighlight {}
  628
  629#[derive(Debug, Clone)]
  630struct InlineDiagnostic {
  631    message: SharedString,
  632    group_id: usize,
  633    is_primary: bool,
  634    start: Point,
  635    severity: lsp::DiagnosticSeverity,
  636}
  637
  638pub enum MenuInlineCompletionsPolicy {
  639    Never,
  640    ByProvider,
  641}
  642
  643pub enum EditPredictionPreview {
  644    /// Modifier is not pressed
  645    Inactive { released_too_fast: bool },
  646    /// Modifier pressed
  647    Active {
  648        since: Instant,
  649        previous_scroll_position: Option<ScrollAnchor>,
  650    },
  651}
  652
  653impl EditPredictionPreview {
  654    pub fn released_too_fast(&self) -> bool {
  655        match self {
  656            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  657            EditPredictionPreview::Active { .. } => false,
  658        }
  659    }
  660
  661    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  662        if let EditPredictionPreview::Active {
  663            previous_scroll_position,
  664            ..
  665        } = self
  666        {
  667            *previous_scroll_position = scroll_position;
  668        }
  669    }
  670}
  671
  672pub struct ContextMenuOptions {
  673    pub min_entries_visible: usize,
  674    pub max_entries_visible: usize,
  675    pub placement: Option<ContextMenuPlacement>,
  676}
  677
  678#[derive(Debug, Clone, PartialEq, Eq)]
  679pub enum ContextMenuPlacement {
  680    Above,
  681    Below,
  682}
  683
  684#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  685struct EditorActionId(usize);
  686
  687impl EditorActionId {
  688    pub fn post_inc(&mut self) -> Self {
  689        let answer = self.0;
  690
  691        *self = Self(answer + 1);
  692
  693        Self(answer)
  694    }
  695}
  696
  697// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  698// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  699
  700type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  701type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  702
  703#[derive(Default)]
  704struct ScrollbarMarkerState {
  705    scrollbar_size: Size<Pixels>,
  706    dirty: bool,
  707    markers: Arc<[PaintQuad]>,
  708    pending_refresh: Option<Task<Result<()>>>,
  709}
  710
  711impl ScrollbarMarkerState {
  712    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  713        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  714    }
  715}
  716
  717#[derive(Clone, Copy, PartialEq, Eq)]
  718pub enum MinimapVisibility {
  719    Disabled,
  720    Enabled(bool),
  721}
  722
  723impl MinimapVisibility {
  724    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  725        if mode.is_full() {
  726            Self::Enabled(EditorSettings::get_global(cx).minimap.minimap_enabled())
  727        } else {
  728            Self::Disabled
  729        }
  730    }
  731
  732    fn disabled(&self) -> bool {
  733        match *self {
  734            Self::Disabled => true,
  735            _ => false,
  736        }
  737    }
  738
  739    fn visible(&self) -> bool {
  740        match *self {
  741            Self::Enabled(visible) => visible,
  742            _ => false,
  743        }
  744    }
  745
  746    fn toggle_visibility(&self) -> Self {
  747        match *self {
  748            Self::Enabled(visible) => Self::Enabled(!visible),
  749            Self::Disabled => Self::Disabled,
  750        }
  751    }
  752}
  753
  754#[derive(Clone, Debug)]
  755struct RunnableTasks {
  756    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  757    offset: multi_buffer::Anchor,
  758    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  759    column: u32,
  760    // Values of all named captures, including those starting with '_'
  761    extra_variables: HashMap<String, String>,
  762    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  763    context_range: Range<BufferOffset>,
  764}
  765
  766impl RunnableTasks {
  767    fn resolve<'a>(
  768        &'a self,
  769        cx: &'a task::TaskContext,
  770    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  771        self.templates.iter().filter_map(|(kind, template)| {
  772            template
  773                .resolve_task(&kind.to_id_base(), cx)
  774                .map(|task| (kind.clone(), task))
  775        })
  776    }
  777}
  778
  779#[derive(Clone)]
  780struct ResolvedTasks {
  781    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  782    position: Anchor,
  783}
  784
  785#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  786struct BufferOffset(usize);
  787
  788// Addons allow storing per-editor state in other crates (e.g. Vim)
  789pub trait Addon: 'static {
  790    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  791
  792    fn render_buffer_header_controls(
  793        &self,
  794        _: &ExcerptInfo,
  795        _: &Window,
  796        _: &App,
  797    ) -> Option<AnyElement> {
  798        None
  799    }
  800
  801    fn to_any(&self) -> &dyn std::any::Any;
  802
  803    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  804        None
  805    }
  806}
  807
  808/// A set of caret positions, registered when the editor was edited.
  809pub struct ChangeList {
  810    changes: Vec<Vec<Anchor>>,
  811    /// Currently "selected" change.
  812    position: Option<usize>,
  813}
  814
  815impl ChangeList {
  816    pub fn new() -> Self {
  817        Self {
  818            changes: Vec::new(),
  819            position: None,
  820        }
  821    }
  822
  823    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  824    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  825    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  826        if self.changes.is_empty() {
  827            return None;
  828        }
  829
  830        let prev = self.position.unwrap_or(self.changes.len());
  831        let next = if direction == Direction::Prev {
  832            prev.saturating_sub(count)
  833        } else {
  834            (prev + count).min(self.changes.len() - 1)
  835        };
  836        self.position = Some(next);
  837        self.changes.get(next).map(|anchors| anchors.as_slice())
  838    }
  839
  840    /// Adds a new change to the list, resetting the change list position.
  841    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  842        self.position.take();
  843        if pop_state {
  844            self.changes.pop();
  845        }
  846        self.changes.push(new_positions.clone());
  847    }
  848
  849    pub fn last(&self) -> Option<&[Anchor]> {
  850        self.changes.last().map(|anchors| anchors.as_slice())
  851    }
  852}
  853
  854#[derive(Clone)]
  855struct InlineBlamePopoverState {
  856    scroll_handle: ScrollHandle,
  857    commit_message: Option<ParsedCommitMessage>,
  858    markdown: Entity<Markdown>,
  859}
  860
  861struct InlineBlamePopover {
  862    position: gpui::Point<Pixels>,
  863    show_task: Option<Task<()>>,
  864    hide_task: Option<Task<()>>,
  865    popover_bounds: Option<Bounds<Pixels>>,
  866    popover_state: InlineBlamePopoverState,
  867}
  868
  869/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  870/// a breakpoint on them.
  871#[derive(Clone, Copy, Debug)]
  872struct PhantomBreakpointIndicator {
  873    display_row: DisplayRow,
  874    /// There's a small debounce between hovering over the line and showing the indicator.
  875    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  876    is_active: bool,
  877    collides_with_existing_breakpoint: bool,
  878}
  879/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  880///
  881/// See the [module level documentation](self) for more information.
  882pub struct Editor {
  883    focus_handle: FocusHandle,
  884    last_focused_descendant: Option<WeakFocusHandle>,
  885    /// The text buffer being edited
  886    buffer: Entity<MultiBuffer>,
  887    /// Map of how text in the buffer should be displayed.
  888    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  889    pub display_map: Entity<DisplayMap>,
  890    pub selections: SelectionsCollection,
  891    pub scroll_manager: ScrollManager,
  892    /// When inline assist editors are linked, they all render cursors because
  893    /// typing enters text into each of them, even the ones that aren't focused.
  894    pub(crate) show_cursor_when_unfocused: bool,
  895    columnar_selection_tail: Option<Anchor>,
  896    add_selections_state: Option<AddSelectionsState>,
  897    select_next_state: Option<SelectNextState>,
  898    select_prev_state: Option<SelectNextState>,
  899    selection_history: SelectionHistory,
  900    autoclose_regions: Vec<AutocloseRegion>,
  901    snippet_stack: InvalidationStack<SnippetState>,
  902    select_syntax_node_history: SelectSyntaxNodeHistory,
  903    ime_transaction: Option<TransactionId>,
  904    pub diagnostics_max_severity: DiagnosticSeverity,
  905    active_diagnostics: ActiveDiagnostic,
  906    show_inline_diagnostics: bool,
  907    inline_diagnostics_update: Task<()>,
  908    inline_diagnostics_enabled: bool,
  909    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  910    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  911    hard_wrap: Option<usize>,
  912
  913    // TODO: make this a access method
  914    pub project: Option<Entity<Project>>,
  915    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  916    completion_provider: Option<Box<dyn CompletionProvider>>,
  917    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  918    blink_manager: Entity<BlinkManager>,
  919    show_cursor_names: bool,
  920    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  921    pub show_local_selections: bool,
  922    mode: EditorMode,
  923    show_breadcrumbs: bool,
  924    show_gutter: bool,
  925    show_scrollbars: bool,
  926    minimap_visibility: MinimapVisibility,
  927    disable_expand_excerpt_buttons: bool,
  928    show_line_numbers: Option<bool>,
  929    use_relative_line_numbers: Option<bool>,
  930    show_git_diff_gutter: Option<bool>,
  931    show_code_actions: Option<bool>,
  932    show_runnables: Option<bool>,
  933    show_breakpoints: Option<bool>,
  934    show_wrap_guides: Option<bool>,
  935    show_indent_guides: Option<bool>,
  936    placeholder_text: Option<Arc<str>>,
  937    highlight_order: usize,
  938    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  939    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  940    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  941    scrollbar_marker_state: ScrollbarMarkerState,
  942    active_indent_guides_state: ActiveIndentGuidesState,
  943    nav_history: Option<ItemNavHistory>,
  944    context_menu: RefCell<Option<CodeContextMenu>>,
  945    context_menu_options: Option<ContextMenuOptions>,
  946    mouse_context_menu: Option<MouseContextMenu>,
  947    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  948    inline_blame_popover: Option<InlineBlamePopover>,
  949    signature_help_state: SignatureHelpState,
  950    auto_signature_help: Option<bool>,
  951    find_all_references_task_sources: Vec<Anchor>,
  952    next_completion_id: CompletionId,
  953    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  954    code_actions_task: Option<Task<Result<()>>>,
  955    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  956    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  957    document_highlights_task: Option<Task<()>>,
  958    linked_editing_range_task: Option<Task<Option<()>>>,
  959    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
  960    pending_rename: Option<RenameState>,
  961    searchable: bool,
  962    cursor_shape: CursorShape,
  963    current_line_highlight: Option<CurrentLineHighlight>,
  964    collapse_matches: bool,
  965    autoindent_mode: Option<AutoindentMode>,
  966    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
  967    input_enabled: bool,
  968    use_modal_editing: bool,
  969    read_only: bool,
  970    leader_id: Option<CollaboratorId>,
  971    remote_id: Option<ViewId>,
  972    pub hover_state: HoverState,
  973    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
  974    gutter_hovered: bool,
  975    hovered_link_state: Option<HoveredLinkState>,
  976    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
  977    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
  978    active_inline_completion: Option<InlineCompletionState>,
  979    /// Used to prevent flickering as the user types while the menu is open
  980    stale_inline_completion_in_menu: Option<InlineCompletionState>,
  981    edit_prediction_settings: EditPredictionSettings,
  982    inline_completions_hidden_for_vim_mode: bool,
  983    show_inline_completions_override: Option<bool>,
  984    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
  985    edit_prediction_preview: EditPredictionPreview,
  986    edit_prediction_indent_conflict: bool,
  987    edit_prediction_requires_modifier_in_indent_conflict: bool,
  988    inlay_hint_cache: InlayHintCache,
  989    next_inlay_id: usize,
  990    _subscriptions: Vec<Subscription>,
  991    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
  992    gutter_dimensions: GutterDimensions,
  993    style: Option<EditorStyle>,
  994    text_style_refinement: Option<TextStyleRefinement>,
  995    next_editor_action_id: EditorActionId,
  996    editor_actions:
  997        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
  998    use_autoclose: bool,
  999    use_auto_surround: bool,
 1000    auto_replace_emoji_shortcode: bool,
 1001    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1002    show_git_blame_gutter: bool,
 1003    show_git_blame_inline: bool,
 1004    show_git_blame_inline_delay_task: Option<Task<()>>,
 1005    git_blame_inline_enabled: bool,
 1006    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1007    serialize_dirty_buffers: bool,
 1008    show_selection_menu: Option<bool>,
 1009    blame: Option<Entity<GitBlame>>,
 1010    blame_subscription: Option<Subscription>,
 1011    custom_context_menu: Option<
 1012        Box<
 1013            dyn 'static
 1014                + Fn(
 1015                    &mut Self,
 1016                    DisplayPoint,
 1017                    &mut Window,
 1018                    &mut Context<Self>,
 1019                ) -> Option<Entity<ui::ContextMenu>>,
 1020        >,
 1021    >,
 1022    last_bounds: Option<Bounds<Pixels>>,
 1023    last_position_map: Option<Rc<PositionMap>>,
 1024    expect_bounds_change: Option<Bounds<Pixels>>,
 1025    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1026    tasks_update_task: Option<Task<()>>,
 1027    breakpoint_store: Option<Entity<BreakpointStore>>,
 1028    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1029    in_project_search: bool,
 1030    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1031    breadcrumb_header: Option<String>,
 1032    focused_block: Option<FocusedBlock>,
 1033    next_scroll_position: NextScrollCursorCenterTopBottom,
 1034    addons: HashMap<TypeId, Box<dyn Addon>>,
 1035    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1036    load_diff_task: Option<Shared<Task<()>>>,
 1037    /// Whether we are temporarily displaying a diff other than git's
 1038    temporary_diff_override: bool,
 1039    selection_mark_mode: bool,
 1040    toggle_fold_multiple_buffers: Task<()>,
 1041    _scroll_cursor_center_top_bottom_task: Task<()>,
 1042    serialize_selections: Task<()>,
 1043    serialize_folds: Task<()>,
 1044    mouse_cursor_hidden: bool,
 1045    minimap: Option<Entity<Self>>,
 1046    hide_mouse_mode: HideMouseMode,
 1047    pub change_list: ChangeList,
 1048    inline_value_cache: InlineValueCache,
 1049}
 1050
 1051#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1052enum NextScrollCursorCenterTopBottom {
 1053    #[default]
 1054    Center,
 1055    Top,
 1056    Bottom,
 1057}
 1058
 1059impl NextScrollCursorCenterTopBottom {
 1060    fn next(&self) -> Self {
 1061        match self {
 1062            Self::Center => Self::Top,
 1063            Self::Top => Self::Bottom,
 1064            Self::Bottom => Self::Center,
 1065        }
 1066    }
 1067}
 1068
 1069#[derive(Clone)]
 1070pub struct EditorSnapshot {
 1071    pub mode: EditorMode,
 1072    show_gutter: bool,
 1073    show_line_numbers: Option<bool>,
 1074    show_git_diff_gutter: Option<bool>,
 1075    show_runnables: Option<bool>,
 1076    show_breakpoints: Option<bool>,
 1077    git_blame_gutter_max_author_length: Option<usize>,
 1078    pub display_snapshot: DisplaySnapshot,
 1079    pub placeholder_text: Option<Arc<str>>,
 1080    is_focused: bool,
 1081    scroll_anchor: ScrollAnchor,
 1082    ongoing_scroll: OngoingScroll,
 1083    current_line_highlight: CurrentLineHighlight,
 1084    gutter_hovered: bool,
 1085}
 1086
 1087#[derive(Default, Debug, Clone, Copy)]
 1088pub struct GutterDimensions {
 1089    pub left_padding: Pixels,
 1090    pub right_padding: Pixels,
 1091    pub width: Pixels,
 1092    pub margin: Pixels,
 1093    pub git_blame_entries_width: Option<Pixels>,
 1094}
 1095
 1096impl GutterDimensions {
 1097    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1098        Self {
 1099            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1100            ..Default::default()
 1101        }
 1102    }
 1103
 1104    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1105        -cx.text_system().descent(font_id, font_size)
 1106    }
 1107    /// The full width of the space taken up by the gutter.
 1108    pub fn full_width(&self) -> Pixels {
 1109        self.margin + self.width
 1110    }
 1111
 1112    /// The width of the space reserved for the fold indicators,
 1113    /// use alongside 'justify_end' and `gutter_width` to
 1114    /// right align content with the line numbers
 1115    pub fn fold_area_width(&self) -> Pixels {
 1116        self.margin + self.right_padding
 1117    }
 1118}
 1119
 1120#[derive(Debug)]
 1121pub struct RemoteSelection {
 1122    pub replica_id: ReplicaId,
 1123    pub selection: Selection<Anchor>,
 1124    pub cursor_shape: CursorShape,
 1125    pub collaborator_id: CollaboratorId,
 1126    pub line_mode: bool,
 1127    pub user_name: Option<SharedString>,
 1128    pub color: PlayerColor,
 1129}
 1130
 1131#[derive(Clone, Debug)]
 1132struct SelectionHistoryEntry {
 1133    selections: Arc<[Selection<Anchor>]>,
 1134    select_next_state: Option<SelectNextState>,
 1135    select_prev_state: Option<SelectNextState>,
 1136    add_selections_state: Option<AddSelectionsState>,
 1137}
 1138
 1139enum SelectionHistoryMode {
 1140    Normal,
 1141    Undoing,
 1142    Redoing,
 1143}
 1144
 1145#[derive(Clone, PartialEq, Eq, Hash)]
 1146struct HoveredCursor {
 1147    replica_id: u16,
 1148    selection_id: usize,
 1149}
 1150
 1151impl Default for SelectionHistoryMode {
 1152    fn default() -> Self {
 1153        Self::Normal
 1154    }
 1155}
 1156
 1157#[derive(Default)]
 1158struct SelectionHistory {
 1159    #[allow(clippy::type_complexity)]
 1160    selections_by_transaction:
 1161        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1162    mode: SelectionHistoryMode,
 1163    undo_stack: VecDeque<SelectionHistoryEntry>,
 1164    redo_stack: VecDeque<SelectionHistoryEntry>,
 1165}
 1166
 1167impl SelectionHistory {
 1168    fn insert_transaction(
 1169        &mut self,
 1170        transaction_id: TransactionId,
 1171        selections: Arc<[Selection<Anchor>]>,
 1172    ) {
 1173        self.selections_by_transaction
 1174            .insert(transaction_id, (selections, None));
 1175    }
 1176
 1177    #[allow(clippy::type_complexity)]
 1178    fn transaction(
 1179        &self,
 1180        transaction_id: TransactionId,
 1181    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1182        self.selections_by_transaction.get(&transaction_id)
 1183    }
 1184
 1185    #[allow(clippy::type_complexity)]
 1186    fn transaction_mut(
 1187        &mut self,
 1188        transaction_id: TransactionId,
 1189    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1190        self.selections_by_transaction.get_mut(&transaction_id)
 1191    }
 1192
 1193    fn push(&mut self, entry: SelectionHistoryEntry) {
 1194        if !entry.selections.is_empty() {
 1195            match self.mode {
 1196                SelectionHistoryMode::Normal => {
 1197                    self.push_undo(entry);
 1198                    self.redo_stack.clear();
 1199                }
 1200                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1201                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1202            }
 1203        }
 1204    }
 1205
 1206    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1207        if self
 1208            .undo_stack
 1209            .back()
 1210            .map_or(true, |e| e.selections != entry.selections)
 1211        {
 1212            self.undo_stack.push_back(entry);
 1213            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1214                self.undo_stack.pop_front();
 1215            }
 1216        }
 1217    }
 1218
 1219    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1220        if self
 1221            .redo_stack
 1222            .back()
 1223            .map_or(true, |e| e.selections != entry.selections)
 1224        {
 1225            self.redo_stack.push_back(entry);
 1226            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1227                self.redo_stack.pop_front();
 1228            }
 1229        }
 1230    }
 1231}
 1232
 1233#[derive(Clone, Copy)]
 1234pub struct RowHighlightOptions {
 1235    pub autoscroll: bool,
 1236    pub include_gutter: bool,
 1237}
 1238
 1239impl Default for RowHighlightOptions {
 1240    fn default() -> Self {
 1241        Self {
 1242            autoscroll: Default::default(),
 1243            include_gutter: true,
 1244        }
 1245    }
 1246}
 1247
 1248struct RowHighlight {
 1249    index: usize,
 1250    range: Range<Anchor>,
 1251    color: Hsla,
 1252    options: RowHighlightOptions,
 1253    type_id: TypeId,
 1254}
 1255
 1256#[derive(Clone, Debug)]
 1257struct AddSelectionsState {
 1258    above: bool,
 1259    stack: Vec<usize>,
 1260}
 1261
 1262#[derive(Clone)]
 1263struct SelectNextState {
 1264    query: AhoCorasick,
 1265    wordwise: bool,
 1266    done: bool,
 1267}
 1268
 1269impl std::fmt::Debug for SelectNextState {
 1270    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1271        f.debug_struct(std::any::type_name::<Self>())
 1272            .field("wordwise", &self.wordwise)
 1273            .field("done", &self.done)
 1274            .finish()
 1275    }
 1276}
 1277
 1278#[derive(Debug)]
 1279struct AutocloseRegion {
 1280    selection_id: usize,
 1281    range: Range<Anchor>,
 1282    pair: BracketPair,
 1283}
 1284
 1285#[derive(Debug)]
 1286struct SnippetState {
 1287    ranges: Vec<Vec<Range<Anchor>>>,
 1288    active_index: usize,
 1289    choices: Vec<Option<Vec<String>>>,
 1290}
 1291
 1292#[doc(hidden)]
 1293pub struct RenameState {
 1294    pub range: Range<Anchor>,
 1295    pub old_name: Arc<str>,
 1296    pub editor: Entity<Editor>,
 1297    block_id: CustomBlockId,
 1298}
 1299
 1300struct InvalidationStack<T>(Vec<T>);
 1301
 1302struct RegisteredInlineCompletionProvider {
 1303    provider: Arc<dyn InlineCompletionProviderHandle>,
 1304    _subscription: Subscription,
 1305}
 1306
 1307#[derive(Debug, PartialEq, Eq)]
 1308pub struct ActiveDiagnosticGroup {
 1309    pub active_range: Range<Anchor>,
 1310    pub active_message: String,
 1311    pub group_id: usize,
 1312    pub blocks: HashSet<CustomBlockId>,
 1313}
 1314
 1315#[derive(Debug, PartialEq, Eq)]
 1316
 1317pub(crate) enum ActiveDiagnostic {
 1318    None,
 1319    All,
 1320    Group(ActiveDiagnosticGroup),
 1321}
 1322
 1323#[derive(Serialize, Deserialize, Clone, Debug)]
 1324pub struct ClipboardSelection {
 1325    /// The number of bytes in this selection.
 1326    pub len: usize,
 1327    /// Whether this was a full-line selection.
 1328    pub is_entire_line: bool,
 1329    /// The indentation of the first line when this content was originally copied.
 1330    pub first_line_indent: u32,
 1331}
 1332
 1333// selections, scroll behavior, was newest selection reversed
 1334type SelectSyntaxNodeHistoryState = (
 1335    Box<[Selection<usize>]>,
 1336    SelectSyntaxNodeScrollBehavior,
 1337    bool,
 1338);
 1339
 1340#[derive(Default)]
 1341struct SelectSyntaxNodeHistory {
 1342    stack: Vec<SelectSyntaxNodeHistoryState>,
 1343    // disable temporarily to allow changing selections without losing the stack
 1344    pub disable_clearing: bool,
 1345}
 1346
 1347impl SelectSyntaxNodeHistory {
 1348    pub fn try_clear(&mut self) {
 1349        if !self.disable_clearing {
 1350            self.stack.clear();
 1351        }
 1352    }
 1353
 1354    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1355        self.stack.push(selection);
 1356    }
 1357
 1358    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1359        self.stack.pop()
 1360    }
 1361}
 1362
 1363enum SelectSyntaxNodeScrollBehavior {
 1364    CursorTop,
 1365    FitSelection,
 1366    CursorBottom,
 1367}
 1368
 1369#[derive(Debug)]
 1370pub(crate) struct NavigationData {
 1371    cursor_anchor: Anchor,
 1372    cursor_position: Point,
 1373    scroll_anchor: ScrollAnchor,
 1374    scroll_top_row: u32,
 1375}
 1376
 1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1378pub enum GotoDefinitionKind {
 1379    Symbol,
 1380    Declaration,
 1381    Type,
 1382    Implementation,
 1383}
 1384
 1385#[derive(Debug, Clone)]
 1386enum InlayHintRefreshReason {
 1387    ModifiersChanged(bool),
 1388    Toggle(bool),
 1389    SettingsChange(InlayHintSettings),
 1390    NewLinesShown,
 1391    BufferEdited(HashSet<Arc<Language>>),
 1392    RefreshRequested,
 1393    ExcerptsRemoved(Vec<ExcerptId>),
 1394}
 1395
 1396impl InlayHintRefreshReason {
 1397    fn description(&self) -> &'static str {
 1398        match self {
 1399            Self::ModifiersChanged(_) => "modifiers changed",
 1400            Self::Toggle(_) => "toggle",
 1401            Self::SettingsChange(_) => "settings change",
 1402            Self::NewLinesShown => "new lines shown",
 1403            Self::BufferEdited(_) => "buffer edited",
 1404            Self::RefreshRequested => "refresh requested",
 1405            Self::ExcerptsRemoved(_) => "excerpts removed",
 1406        }
 1407    }
 1408}
 1409
 1410pub enum FormatTarget {
 1411    Buffers,
 1412    Ranges(Vec<Range<MultiBufferPoint>>),
 1413}
 1414
 1415pub(crate) struct FocusedBlock {
 1416    id: BlockId,
 1417    focus_handle: WeakFocusHandle,
 1418}
 1419
 1420#[derive(Clone)]
 1421enum JumpData {
 1422    MultiBufferRow {
 1423        row: MultiBufferRow,
 1424        line_offset_from_top: u32,
 1425    },
 1426    MultiBufferPoint {
 1427        excerpt_id: ExcerptId,
 1428        position: Point,
 1429        anchor: text::Anchor,
 1430        line_offset_from_top: u32,
 1431    },
 1432}
 1433
 1434pub enum MultibufferSelectionMode {
 1435    First,
 1436    All,
 1437}
 1438
 1439#[derive(Clone, Copy, Debug, Default)]
 1440pub struct RewrapOptions {
 1441    pub override_language_settings: bool,
 1442    pub preserve_existing_whitespace: bool,
 1443}
 1444
 1445impl Editor {
 1446    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1447        let buffer = cx.new(|cx| Buffer::local("", cx));
 1448        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1449        Self::new(
 1450            EditorMode::SingleLine { auto_width: false },
 1451            buffer,
 1452            None,
 1453            window,
 1454            cx,
 1455        )
 1456    }
 1457
 1458    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1459        let buffer = cx.new(|cx| Buffer::local("", cx));
 1460        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1461        Self::new(EditorMode::full(), buffer, None, window, cx)
 1462    }
 1463
 1464    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1465        let buffer = cx.new(|cx| Buffer::local("", cx));
 1466        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1467        Self::new(
 1468            EditorMode::SingleLine { auto_width: true },
 1469            buffer,
 1470            None,
 1471            window,
 1472            cx,
 1473        )
 1474    }
 1475
 1476    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1477        let buffer = cx.new(|cx| Buffer::local("", cx));
 1478        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1479        Self::new(
 1480            EditorMode::AutoHeight { max_lines },
 1481            buffer,
 1482            None,
 1483            window,
 1484            cx,
 1485        )
 1486    }
 1487
 1488    pub fn for_buffer(
 1489        buffer: Entity<Buffer>,
 1490        project: Option<Entity<Project>>,
 1491        window: &mut Window,
 1492        cx: &mut Context<Self>,
 1493    ) -> Self {
 1494        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1495        Self::new(EditorMode::full(), buffer, project, window, cx)
 1496    }
 1497
 1498    pub fn for_multibuffer(
 1499        buffer: Entity<MultiBuffer>,
 1500        project: Option<Entity<Project>>,
 1501        window: &mut Window,
 1502        cx: &mut Context<Self>,
 1503    ) -> Self {
 1504        Self::new(EditorMode::full(), buffer, project, window, cx)
 1505    }
 1506
 1507    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1508        let mut clone = Self::new(
 1509            self.mode.clone(),
 1510            self.buffer.clone(),
 1511            self.project.clone(),
 1512            window,
 1513            cx,
 1514        );
 1515        self.display_map.update(cx, |display_map, cx| {
 1516            let snapshot = display_map.snapshot(cx);
 1517            clone.display_map.update(cx, |display_map, cx| {
 1518                display_map.set_state(&snapshot, cx);
 1519            });
 1520        });
 1521        clone.folds_did_change(cx);
 1522        clone.selections.clone_state(&self.selections);
 1523        clone.scroll_manager.clone_state(&self.scroll_manager);
 1524        clone.searchable = self.searchable;
 1525        clone.read_only = self.read_only;
 1526        clone
 1527    }
 1528
 1529    pub fn new(
 1530        mode: EditorMode,
 1531        buffer: Entity<MultiBuffer>,
 1532        project: Option<Entity<Project>>,
 1533        window: &mut Window,
 1534        cx: &mut Context<Self>,
 1535    ) -> Self {
 1536        Editor::new_internal(mode, buffer, project, None, window, cx)
 1537    }
 1538
 1539    fn new_internal(
 1540        mode: EditorMode,
 1541        buffer: Entity<MultiBuffer>,
 1542        project: Option<Entity<Project>>,
 1543        display_map: Option<Entity<DisplayMap>>,
 1544        window: &mut Window,
 1545        cx: &mut Context<Self>,
 1546    ) -> Self {
 1547        debug_assert!(
 1548            display_map.is_none() || mode.is_minimap(),
 1549            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1550        );
 1551
 1552        let full_mode = mode.is_full();
 1553        let diagnostics_max_severity = if full_mode {
 1554            EditorSettings::get_global(cx)
 1555                .diagnostics_max_severity
 1556                .unwrap_or(DiagnosticSeverity::Hint)
 1557        } else {
 1558            DiagnosticSeverity::Off
 1559        };
 1560        let style = window.text_style();
 1561        let font_size = style.font_size.to_pixels(window.rem_size());
 1562        let editor = cx.entity().downgrade();
 1563        let fold_placeholder = FoldPlaceholder {
 1564            constrain_width: true,
 1565            render: Arc::new(move |fold_id, fold_range, cx| {
 1566                let editor = editor.clone();
 1567                div()
 1568                    .id(fold_id)
 1569                    .bg(cx.theme().colors().ghost_element_background)
 1570                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1571                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1572                    .rounded_xs()
 1573                    .size_full()
 1574                    .cursor_pointer()
 1575                    .child("")
 1576                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1577                    .on_click(move |_, _window, cx| {
 1578                        editor
 1579                            .update(cx, |editor, cx| {
 1580                                editor.unfold_ranges(
 1581                                    &[fold_range.start..fold_range.end],
 1582                                    true,
 1583                                    false,
 1584                                    cx,
 1585                                );
 1586                                cx.stop_propagation();
 1587                            })
 1588                            .ok();
 1589                    })
 1590                    .into_any()
 1591            }),
 1592            merge_adjacent: true,
 1593            ..FoldPlaceholder::default()
 1594        };
 1595        let display_map = display_map.unwrap_or_else(|| {
 1596            cx.new(|cx| {
 1597                DisplayMap::new(
 1598                    buffer.clone(),
 1599                    style.font(),
 1600                    font_size,
 1601                    None,
 1602                    FILE_HEADER_HEIGHT,
 1603                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1604                    fold_placeholder,
 1605                    diagnostics_max_severity,
 1606                    cx,
 1607                )
 1608            })
 1609        });
 1610
 1611        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1612
 1613        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1614
 1615        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1616            .then(|| language_settings::SoftWrap::None);
 1617
 1618        let mut project_subscriptions = Vec::new();
 1619        if mode.is_full() {
 1620            if let Some(project) = project.as_ref() {
 1621                project_subscriptions.push(cx.subscribe_in(
 1622                    project,
 1623                    window,
 1624                    |editor, _, event, window, cx| match event {
 1625                        project::Event::RefreshCodeLens => {
 1626                            // we always query lens with actions, without storing them, always refreshing them
 1627                        }
 1628                        project::Event::RefreshInlayHints => {
 1629                            editor
 1630                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1631                        }
 1632                        project::Event::SnippetEdit(id, snippet_edits) => {
 1633                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1634                                let focus_handle = editor.focus_handle(cx);
 1635                                if focus_handle.is_focused(window) {
 1636                                    let snapshot = buffer.read(cx).snapshot();
 1637                                    for (range, snippet) in snippet_edits {
 1638                                        let editor_range =
 1639                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1640                                        editor
 1641                                            .insert_snippet(
 1642                                                &[editor_range],
 1643                                                snippet.clone(),
 1644                                                window,
 1645                                                cx,
 1646                                            )
 1647                                            .ok();
 1648                                    }
 1649                                }
 1650                            }
 1651                        }
 1652                        _ => {}
 1653                    },
 1654                ));
 1655                if let Some(task_inventory) = project
 1656                    .read(cx)
 1657                    .task_store()
 1658                    .read(cx)
 1659                    .task_inventory()
 1660                    .cloned()
 1661                {
 1662                    project_subscriptions.push(cx.observe_in(
 1663                        &task_inventory,
 1664                        window,
 1665                        |editor, _, window, cx| {
 1666                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1667                        },
 1668                    ));
 1669                };
 1670
 1671                project_subscriptions.push(cx.subscribe_in(
 1672                    &project.read(cx).breakpoint_store(),
 1673                    window,
 1674                    |editor, _, event, window, cx| match event {
 1675                        BreakpointStoreEvent::ClearDebugLines => {
 1676                            editor.clear_row_highlights::<ActiveDebugLine>();
 1677                            editor.refresh_inline_values(cx);
 1678                        }
 1679                        BreakpointStoreEvent::SetDebugLine => {
 1680                            if editor.go_to_active_debug_line(window, cx) {
 1681                                cx.stop_propagation();
 1682                            }
 1683
 1684                            editor.refresh_inline_values(cx);
 1685                        }
 1686                        _ => {}
 1687                    },
 1688                ));
 1689            }
 1690        }
 1691
 1692        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1693
 1694        let inlay_hint_settings =
 1695            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1696        let focus_handle = cx.focus_handle();
 1697        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1698            .detach();
 1699        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1700            .detach();
 1701        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1702            .detach();
 1703        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1704            .detach();
 1705
 1706        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1707            Some(false)
 1708        } else {
 1709            None
 1710        };
 1711
 1712        let breakpoint_store = match (&mode, project.as_ref()) {
 1713            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1714            _ => None,
 1715        };
 1716
 1717        let mut code_action_providers = Vec::new();
 1718        let mut load_uncommitted_diff = None;
 1719        if let Some(project) = project.clone() {
 1720            load_uncommitted_diff = Some(
 1721                update_uncommitted_diff_for_buffer(
 1722                    cx.entity(),
 1723                    &project,
 1724                    buffer.read(cx).all_buffers(),
 1725                    buffer.clone(),
 1726                    cx,
 1727                )
 1728                .shared(),
 1729            );
 1730            code_action_providers.push(Rc::new(project) as Rc<_>);
 1731        }
 1732
 1733        let mut this = Self {
 1734            focus_handle,
 1735            show_cursor_when_unfocused: false,
 1736            last_focused_descendant: None,
 1737            buffer: buffer.clone(),
 1738            display_map: display_map.clone(),
 1739            selections,
 1740            scroll_manager: ScrollManager::new(cx),
 1741            columnar_selection_tail: None,
 1742            add_selections_state: None,
 1743            select_next_state: None,
 1744            select_prev_state: None,
 1745            selection_history: SelectionHistory::default(),
 1746            autoclose_regions: Vec::new(),
 1747            snippet_stack: InvalidationStack::default(),
 1748            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1749            ime_transaction: None,
 1750            active_diagnostics: ActiveDiagnostic::None,
 1751            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1752            inline_diagnostics_update: Task::ready(()),
 1753            inline_diagnostics: Vec::new(),
 1754            soft_wrap_mode_override,
 1755            diagnostics_max_severity,
 1756            hard_wrap: None,
 1757            completion_provider: project.clone().map(|project| Box::new(project) as _),
 1758            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1759            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1760            project,
 1761            blink_manager: blink_manager.clone(),
 1762            show_local_selections: true,
 1763            show_scrollbars: full_mode,
 1764            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1765            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1766            show_gutter: mode.is_full(),
 1767            show_line_numbers: None,
 1768            use_relative_line_numbers: None,
 1769            disable_expand_excerpt_buttons: false,
 1770            show_git_diff_gutter: None,
 1771            show_code_actions: None,
 1772            show_runnables: None,
 1773            show_breakpoints: None,
 1774            show_wrap_guides: None,
 1775            show_indent_guides,
 1776            placeholder_text: None,
 1777            highlight_order: 0,
 1778            highlighted_rows: HashMap::default(),
 1779            background_highlights: TreeMap::default(),
 1780            gutter_highlights: TreeMap::default(),
 1781            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1782            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1783            nav_history: None,
 1784            context_menu: RefCell::new(None),
 1785            context_menu_options: None,
 1786            mouse_context_menu: None,
 1787            completion_tasks: Vec::new(),
 1788            inline_blame_popover: None,
 1789            signature_help_state: SignatureHelpState::default(),
 1790            auto_signature_help: None,
 1791            find_all_references_task_sources: Vec::new(),
 1792            next_completion_id: 0,
 1793            next_inlay_id: 0,
 1794            code_action_providers,
 1795            available_code_actions: None,
 1796            code_actions_task: None,
 1797            quick_selection_highlight_task: None,
 1798            debounced_selection_highlight_task: None,
 1799            document_highlights_task: None,
 1800            linked_editing_range_task: None,
 1801            pending_rename: None,
 1802            searchable: true,
 1803            cursor_shape: EditorSettings::get_global(cx)
 1804                .cursor_shape
 1805                .unwrap_or_default(),
 1806            current_line_highlight: None,
 1807            autoindent_mode: Some(AutoindentMode::EachLine),
 1808            collapse_matches: false,
 1809            workspace: None,
 1810            input_enabled: true,
 1811            use_modal_editing: mode.is_full(),
 1812            read_only: mode.is_minimap(),
 1813            use_autoclose: true,
 1814            use_auto_surround: true,
 1815            auto_replace_emoji_shortcode: false,
 1816            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1817            leader_id: None,
 1818            remote_id: None,
 1819            hover_state: HoverState::default(),
 1820            pending_mouse_down: None,
 1821            hovered_link_state: None,
 1822            edit_prediction_provider: None,
 1823            active_inline_completion: None,
 1824            stale_inline_completion_in_menu: None,
 1825            edit_prediction_preview: EditPredictionPreview::Inactive {
 1826                released_too_fast: false,
 1827            },
 1828            inline_diagnostics_enabled: mode.is_full(),
 1829            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1830            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1831
 1832            gutter_hovered: false,
 1833            pixel_position_of_newest_cursor: None,
 1834            last_bounds: None,
 1835            last_position_map: None,
 1836            expect_bounds_change: None,
 1837            gutter_dimensions: GutterDimensions::default(),
 1838            style: None,
 1839            show_cursor_names: false,
 1840            hovered_cursors: HashMap::default(),
 1841            next_editor_action_id: EditorActionId::default(),
 1842            editor_actions: Rc::default(),
 1843            inline_completions_hidden_for_vim_mode: false,
 1844            show_inline_completions_override: None,
 1845            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1846            edit_prediction_settings: EditPredictionSettings::Disabled,
 1847            edit_prediction_indent_conflict: false,
 1848            edit_prediction_requires_modifier_in_indent_conflict: true,
 1849            custom_context_menu: None,
 1850            show_git_blame_gutter: false,
 1851            show_git_blame_inline: false,
 1852            show_selection_menu: None,
 1853            show_git_blame_inline_delay_task: None,
 1854            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1855            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1856            serialize_dirty_buffers: !mode.is_minimap()
 1857                && ProjectSettings::get_global(cx)
 1858                    .session
 1859                    .restore_unsaved_buffers,
 1860            blame: None,
 1861            blame_subscription: None,
 1862            tasks: BTreeMap::default(),
 1863
 1864            breakpoint_store,
 1865            gutter_breakpoint_indicator: (None, None),
 1866            _subscriptions: vec![
 1867                cx.observe(&buffer, Self::on_buffer_changed),
 1868                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1869                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1870                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1871                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1872                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1873                cx.observe_window_activation(window, |editor, window, cx| {
 1874                    let active = window.is_window_active();
 1875                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1876                        if active {
 1877                            blink_manager.enable(cx);
 1878                        } else {
 1879                            blink_manager.disable(cx);
 1880                        }
 1881                    });
 1882                }),
 1883            ],
 1884            tasks_update_task: None,
 1885            linked_edit_ranges: Default::default(),
 1886            in_project_search: false,
 1887            previous_search_ranges: None,
 1888            breadcrumb_header: None,
 1889            focused_block: None,
 1890            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1891            addons: HashMap::default(),
 1892            registered_buffers: HashMap::default(),
 1893            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1894            selection_mark_mode: false,
 1895            toggle_fold_multiple_buffers: Task::ready(()),
 1896            serialize_selections: Task::ready(()),
 1897            serialize_folds: Task::ready(()),
 1898            text_style_refinement: None,
 1899            load_diff_task: load_uncommitted_diff,
 1900            temporary_diff_override: false,
 1901            mouse_cursor_hidden: false,
 1902            minimap: None,
 1903            hide_mouse_mode: EditorSettings::get_global(cx)
 1904                .hide_mouse
 1905                .unwrap_or_default(),
 1906            change_list: ChangeList::new(),
 1907            mode,
 1908        };
 1909        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1910            this._subscriptions
 1911                .push(cx.observe(breakpoints, |_, _, cx| {
 1912                    cx.notify();
 1913                }));
 1914        }
 1915        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1916        this._subscriptions.extend(project_subscriptions);
 1917
 1918        this._subscriptions.push(cx.subscribe_in(
 1919            &cx.entity(),
 1920            window,
 1921            |editor, _, e: &EditorEvent, window, cx| match e {
 1922                EditorEvent::ScrollPositionChanged { local, .. } => {
 1923                    if *local {
 1924                        let new_anchor = editor.scroll_manager.anchor();
 1925                        let snapshot = editor.snapshot(window, cx);
 1926                        editor.update_restoration_data(cx, move |data| {
 1927                            data.scroll_position = (
 1928                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1929                                new_anchor.offset,
 1930                            );
 1931                        });
 1932                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1933                        editor.inline_blame_popover.take();
 1934                    }
 1935                }
 1936                EditorEvent::Edited { .. } => {
 1937                    if !vim_enabled(cx) {
 1938                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1939                        let pop_state = editor
 1940                            .change_list
 1941                            .last()
 1942                            .map(|previous| {
 1943                                previous.len() == selections.len()
 1944                                    && previous.iter().enumerate().all(|(ix, p)| {
 1945                                        p.to_display_point(&map).row()
 1946                                            == selections[ix].head().row()
 1947                                    })
 1948                            })
 1949                            .unwrap_or(false);
 1950                        let new_positions = selections
 1951                            .into_iter()
 1952                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 1953                            .collect();
 1954                        editor
 1955                            .change_list
 1956                            .push_to_change_list(pop_state, new_positions);
 1957                    }
 1958                }
 1959                _ => (),
 1960            },
 1961        ));
 1962
 1963        if let Some(dap_store) = this
 1964            .project
 1965            .as_ref()
 1966            .map(|project| project.read(cx).dap_store())
 1967        {
 1968            let weak_editor = cx.weak_entity();
 1969
 1970            this._subscriptions
 1971                .push(
 1972                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 1973                        let session_entity = cx.entity();
 1974                        weak_editor
 1975                            .update(cx, |editor, cx| {
 1976                                editor._subscriptions.push(
 1977                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 1978                                );
 1979                            })
 1980                            .ok();
 1981                    }),
 1982                );
 1983
 1984            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 1985                this._subscriptions
 1986                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 1987            }
 1988        }
 1989
 1990        this.end_selection(window, cx);
 1991        this.scroll_manager.show_scrollbars(window, cx);
 1992        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 1993
 1994        if full_mode {
 1995            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 1996            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 1997
 1998            if this.git_blame_inline_enabled {
 1999                this.start_git_blame_inline(false, window, cx);
 2000            }
 2001
 2002            this.go_to_active_debug_line(window, cx);
 2003
 2004            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2005                if let Some(project) = this.project.as_ref() {
 2006                    let handle = project.update(cx, |project, cx| {
 2007                        project.register_buffer_with_language_servers(&buffer, cx)
 2008                    });
 2009                    this.registered_buffers
 2010                        .insert(buffer.read(cx).remote_id(), handle);
 2011                }
 2012            }
 2013
 2014            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2015        }
 2016
 2017        this.report_editor_event("Editor Opened", None, cx);
 2018        this
 2019    }
 2020
 2021    pub fn deploy_mouse_context_menu(
 2022        &mut self,
 2023        position: gpui::Point<Pixels>,
 2024        context_menu: Entity<ContextMenu>,
 2025        window: &mut Window,
 2026        cx: &mut Context<Self>,
 2027    ) {
 2028        self.mouse_context_menu = Some(MouseContextMenu::new(
 2029            self,
 2030            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2031            context_menu,
 2032            window,
 2033            cx,
 2034        ));
 2035    }
 2036
 2037    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2038        self.mouse_context_menu
 2039            .as_ref()
 2040            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2041    }
 2042
 2043    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2044        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2045    }
 2046
 2047    fn key_context_internal(
 2048        &self,
 2049        has_active_edit_prediction: bool,
 2050        window: &Window,
 2051        cx: &App,
 2052    ) -> KeyContext {
 2053        let mut key_context = KeyContext::new_with_defaults();
 2054        key_context.add("Editor");
 2055        let mode = match self.mode {
 2056            EditorMode::SingleLine { .. } => "single_line",
 2057            EditorMode::AutoHeight { .. } => "auto_height",
 2058            EditorMode::Minimap { .. } => "minimap",
 2059            EditorMode::Full { .. } => "full",
 2060        };
 2061
 2062        if EditorSettings::jupyter_enabled(cx) {
 2063            key_context.add("jupyter");
 2064        }
 2065
 2066        key_context.set("mode", mode);
 2067        if self.pending_rename.is_some() {
 2068            key_context.add("renaming");
 2069        }
 2070
 2071        match self.context_menu.borrow().as_ref() {
 2072            Some(CodeContextMenu::Completions(_)) => {
 2073                key_context.add("menu");
 2074                key_context.add("showing_completions");
 2075            }
 2076            Some(CodeContextMenu::CodeActions(_)) => {
 2077                key_context.add("menu");
 2078                key_context.add("showing_code_actions")
 2079            }
 2080            None => {}
 2081        }
 2082
 2083        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2084        if !self.focus_handle(cx).contains_focused(window, cx)
 2085            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2086        {
 2087            for addon in self.addons.values() {
 2088                addon.extend_key_context(&mut key_context, cx)
 2089            }
 2090        }
 2091
 2092        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2093            if let Some(extension) = singleton_buffer
 2094                .read(cx)
 2095                .file()
 2096                .and_then(|file| file.path().extension()?.to_str())
 2097            {
 2098                key_context.set("extension", extension.to_string());
 2099            }
 2100        } else {
 2101            key_context.add("multibuffer");
 2102        }
 2103
 2104        if has_active_edit_prediction {
 2105            if self.edit_prediction_in_conflict() {
 2106                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2107            } else {
 2108                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2109                key_context.add("copilot_suggestion");
 2110            }
 2111        }
 2112
 2113        if self.selection_mark_mode {
 2114            key_context.add("selection_mode");
 2115        }
 2116
 2117        key_context
 2118    }
 2119
 2120    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2121        self.mouse_cursor_hidden = match origin {
 2122            HideMouseCursorOrigin::TypingAction => {
 2123                matches!(
 2124                    self.hide_mouse_mode,
 2125                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2126                )
 2127            }
 2128            HideMouseCursorOrigin::MovementAction => {
 2129                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2130            }
 2131        };
 2132    }
 2133
 2134    pub fn edit_prediction_in_conflict(&self) -> bool {
 2135        if !self.show_edit_predictions_in_menu() {
 2136            return false;
 2137        }
 2138
 2139        let showing_completions = self
 2140            .context_menu
 2141            .borrow()
 2142            .as_ref()
 2143            .map_or(false, |context| {
 2144                matches!(context, CodeContextMenu::Completions(_))
 2145            });
 2146
 2147        showing_completions
 2148            || self.edit_prediction_requires_modifier()
 2149            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2150            // bindings to insert tab characters.
 2151            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2152    }
 2153
 2154    pub fn accept_edit_prediction_keybind(
 2155        &self,
 2156        window: &Window,
 2157        cx: &App,
 2158    ) -> AcceptEditPredictionBinding {
 2159        let key_context = self.key_context_internal(true, window, cx);
 2160        let in_conflict = self.edit_prediction_in_conflict();
 2161
 2162        AcceptEditPredictionBinding(
 2163            window
 2164                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2165                .into_iter()
 2166                .filter(|binding| {
 2167                    !in_conflict
 2168                        || binding
 2169                            .keystrokes()
 2170                            .first()
 2171                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2172                })
 2173                .rev()
 2174                .min_by_key(|binding| {
 2175                    binding
 2176                        .keystrokes()
 2177                        .first()
 2178                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2179                }),
 2180        )
 2181    }
 2182
 2183    pub fn new_file(
 2184        workspace: &mut Workspace,
 2185        _: &workspace::NewFile,
 2186        window: &mut Window,
 2187        cx: &mut Context<Workspace>,
 2188    ) {
 2189        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2190            "Failed to create buffer",
 2191            window,
 2192            cx,
 2193            |e, _, _| match e.error_code() {
 2194                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2195                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2196                e.error_tag("required").unwrap_or("the latest version")
 2197            )),
 2198                _ => None,
 2199            },
 2200        );
 2201    }
 2202
 2203    pub fn new_in_workspace(
 2204        workspace: &mut Workspace,
 2205        window: &mut Window,
 2206        cx: &mut Context<Workspace>,
 2207    ) -> Task<Result<Entity<Editor>>> {
 2208        let project = workspace.project().clone();
 2209        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2210
 2211        cx.spawn_in(window, async move |workspace, cx| {
 2212            let buffer = create.await?;
 2213            workspace.update_in(cx, |workspace, window, cx| {
 2214                let editor =
 2215                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2216                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2217                editor
 2218            })
 2219        })
 2220    }
 2221
 2222    fn new_file_vertical(
 2223        workspace: &mut Workspace,
 2224        _: &workspace::NewFileSplitVertical,
 2225        window: &mut Window,
 2226        cx: &mut Context<Workspace>,
 2227    ) {
 2228        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2229    }
 2230
 2231    fn new_file_horizontal(
 2232        workspace: &mut Workspace,
 2233        _: &workspace::NewFileSplitHorizontal,
 2234        window: &mut Window,
 2235        cx: &mut Context<Workspace>,
 2236    ) {
 2237        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2238    }
 2239
 2240    fn new_file_in_direction(
 2241        workspace: &mut Workspace,
 2242        direction: SplitDirection,
 2243        window: &mut Window,
 2244        cx: &mut Context<Workspace>,
 2245    ) {
 2246        let project = workspace.project().clone();
 2247        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2248
 2249        cx.spawn_in(window, async move |workspace, cx| {
 2250            let buffer = create.await?;
 2251            workspace.update_in(cx, move |workspace, window, cx| {
 2252                workspace.split_item(
 2253                    direction,
 2254                    Box::new(
 2255                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2256                    ),
 2257                    window,
 2258                    cx,
 2259                )
 2260            })?;
 2261            anyhow::Ok(())
 2262        })
 2263        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2264            match e.error_code() {
 2265                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2266                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2267                e.error_tag("required").unwrap_or("the latest version")
 2268            )),
 2269                _ => None,
 2270            }
 2271        });
 2272    }
 2273
 2274    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2275        self.leader_id
 2276    }
 2277
 2278    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2279        &self.buffer
 2280    }
 2281
 2282    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2283        self.workspace.as_ref()?.0.upgrade()
 2284    }
 2285
 2286    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2287        self.buffer().read(cx).title(cx)
 2288    }
 2289
 2290    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2291        let git_blame_gutter_max_author_length = self
 2292            .render_git_blame_gutter(cx)
 2293            .then(|| {
 2294                if let Some(blame) = self.blame.as_ref() {
 2295                    let max_author_length =
 2296                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2297                    Some(max_author_length)
 2298                } else {
 2299                    None
 2300                }
 2301            })
 2302            .flatten();
 2303
 2304        EditorSnapshot {
 2305            mode: self.mode.clone(),
 2306            show_gutter: self.show_gutter,
 2307            show_line_numbers: self.show_line_numbers,
 2308            show_git_diff_gutter: self.show_git_diff_gutter,
 2309            show_runnables: self.show_runnables,
 2310            show_breakpoints: self.show_breakpoints,
 2311            git_blame_gutter_max_author_length,
 2312            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2313            scroll_anchor: self.scroll_manager.anchor(),
 2314            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2315            placeholder_text: self.placeholder_text.clone(),
 2316            is_focused: self.focus_handle.is_focused(window),
 2317            current_line_highlight: self
 2318                .current_line_highlight
 2319                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2320            gutter_hovered: self.gutter_hovered,
 2321        }
 2322    }
 2323
 2324    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2325        self.buffer.read(cx).language_at(point, cx)
 2326    }
 2327
 2328    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2329        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2330    }
 2331
 2332    pub fn active_excerpt(
 2333        &self,
 2334        cx: &App,
 2335    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2336        self.buffer
 2337            .read(cx)
 2338            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2339    }
 2340
 2341    pub fn mode(&self) -> &EditorMode {
 2342        &self.mode
 2343    }
 2344
 2345    pub fn set_mode(&mut self, mode: EditorMode) {
 2346        self.mode = mode;
 2347    }
 2348
 2349    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2350        self.collaboration_hub.as_deref()
 2351    }
 2352
 2353    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2354        self.collaboration_hub = Some(hub);
 2355    }
 2356
 2357    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2358        self.in_project_search = in_project_search;
 2359    }
 2360
 2361    pub fn set_custom_context_menu(
 2362        &mut self,
 2363        f: impl 'static
 2364        + Fn(
 2365            &mut Self,
 2366            DisplayPoint,
 2367            &mut Window,
 2368            &mut Context<Self>,
 2369        ) -> Option<Entity<ui::ContextMenu>>,
 2370    ) {
 2371        self.custom_context_menu = Some(Box::new(f))
 2372    }
 2373
 2374    pub fn set_completion_provider(&mut self, provider: Option<Box<dyn CompletionProvider>>) {
 2375        self.completion_provider = provider;
 2376    }
 2377
 2378    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2379        self.semantics_provider.clone()
 2380    }
 2381
 2382    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2383        self.semantics_provider = provider;
 2384    }
 2385
 2386    pub fn set_edit_prediction_provider<T>(
 2387        &mut self,
 2388        provider: Option<Entity<T>>,
 2389        window: &mut Window,
 2390        cx: &mut Context<Self>,
 2391    ) where
 2392        T: EditPredictionProvider,
 2393    {
 2394        self.edit_prediction_provider =
 2395            provider.map(|provider| RegisteredInlineCompletionProvider {
 2396                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2397                    if this.focus_handle.is_focused(window) {
 2398                        this.update_visible_inline_completion(window, cx);
 2399                    }
 2400                }),
 2401                provider: Arc::new(provider),
 2402            });
 2403        self.update_edit_prediction_settings(cx);
 2404        self.refresh_inline_completion(false, false, window, cx);
 2405    }
 2406
 2407    pub fn placeholder_text(&self) -> Option<&str> {
 2408        self.placeholder_text.as_deref()
 2409    }
 2410
 2411    pub fn set_placeholder_text(
 2412        &mut self,
 2413        placeholder_text: impl Into<Arc<str>>,
 2414        cx: &mut Context<Self>,
 2415    ) {
 2416        let placeholder_text = Some(placeholder_text.into());
 2417        if self.placeholder_text != placeholder_text {
 2418            self.placeholder_text = placeholder_text;
 2419            cx.notify();
 2420        }
 2421    }
 2422
 2423    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2424        self.cursor_shape = cursor_shape;
 2425
 2426        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2427        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2428
 2429        cx.notify();
 2430    }
 2431
 2432    pub fn set_current_line_highlight(
 2433        &mut self,
 2434        current_line_highlight: Option<CurrentLineHighlight>,
 2435    ) {
 2436        self.current_line_highlight = current_line_highlight;
 2437    }
 2438
 2439    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2440        self.collapse_matches = collapse_matches;
 2441    }
 2442
 2443    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2444        let buffers = self.buffer.read(cx).all_buffers();
 2445        let Some(project) = self.project.as_ref() else {
 2446            return;
 2447        };
 2448        project.update(cx, |project, cx| {
 2449            for buffer in buffers {
 2450                self.registered_buffers
 2451                    .entry(buffer.read(cx).remote_id())
 2452                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2453            }
 2454        })
 2455    }
 2456
 2457    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2458        if self.collapse_matches {
 2459            return range.start..range.start;
 2460        }
 2461        range.clone()
 2462    }
 2463
 2464    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2465        if self.display_map.read(cx).clip_at_line_ends != clip {
 2466            self.display_map
 2467                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2468        }
 2469    }
 2470
 2471    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2472        self.input_enabled = input_enabled;
 2473    }
 2474
 2475    pub fn set_inline_completions_hidden_for_vim_mode(
 2476        &mut self,
 2477        hidden: bool,
 2478        window: &mut Window,
 2479        cx: &mut Context<Self>,
 2480    ) {
 2481        if hidden != self.inline_completions_hidden_for_vim_mode {
 2482            self.inline_completions_hidden_for_vim_mode = hidden;
 2483            if hidden {
 2484                self.update_visible_inline_completion(window, cx);
 2485            } else {
 2486                self.refresh_inline_completion(true, false, window, cx);
 2487            }
 2488        }
 2489    }
 2490
 2491    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2492        self.menu_inline_completions_policy = value;
 2493    }
 2494
 2495    pub fn set_autoindent(&mut self, autoindent: bool) {
 2496        if autoindent {
 2497            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2498        } else {
 2499            self.autoindent_mode = None;
 2500        }
 2501    }
 2502
 2503    pub fn read_only(&self, cx: &App) -> bool {
 2504        self.read_only || self.buffer.read(cx).read_only()
 2505    }
 2506
 2507    pub fn set_read_only(&mut self, read_only: bool) {
 2508        self.read_only = read_only;
 2509    }
 2510
 2511    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2512        self.use_autoclose = autoclose;
 2513    }
 2514
 2515    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2516        self.use_auto_surround = auto_surround;
 2517    }
 2518
 2519    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2520        self.auto_replace_emoji_shortcode = auto_replace;
 2521    }
 2522
 2523    pub fn toggle_edit_predictions(
 2524        &mut self,
 2525        _: &ToggleEditPrediction,
 2526        window: &mut Window,
 2527        cx: &mut Context<Self>,
 2528    ) {
 2529        if self.show_inline_completions_override.is_some() {
 2530            self.set_show_edit_predictions(None, window, cx);
 2531        } else {
 2532            let show_edit_predictions = !self.edit_predictions_enabled();
 2533            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2534        }
 2535    }
 2536
 2537    pub fn set_show_edit_predictions(
 2538        &mut self,
 2539        show_edit_predictions: Option<bool>,
 2540        window: &mut Window,
 2541        cx: &mut Context<Self>,
 2542    ) {
 2543        self.show_inline_completions_override = show_edit_predictions;
 2544        self.update_edit_prediction_settings(cx);
 2545
 2546        if let Some(false) = show_edit_predictions {
 2547            self.discard_inline_completion(false, cx);
 2548        } else {
 2549            self.refresh_inline_completion(false, true, window, cx);
 2550        }
 2551    }
 2552
 2553    fn inline_completions_disabled_in_scope(
 2554        &self,
 2555        buffer: &Entity<Buffer>,
 2556        buffer_position: language::Anchor,
 2557        cx: &App,
 2558    ) -> bool {
 2559        let snapshot = buffer.read(cx).snapshot();
 2560        let settings = snapshot.settings_at(buffer_position, cx);
 2561
 2562        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2563            return false;
 2564        };
 2565
 2566        scope.override_name().map_or(false, |scope_name| {
 2567            settings
 2568                .edit_predictions_disabled_in
 2569                .iter()
 2570                .any(|s| s == scope_name)
 2571        })
 2572    }
 2573
 2574    pub fn set_use_modal_editing(&mut self, to: bool) {
 2575        self.use_modal_editing = to;
 2576    }
 2577
 2578    pub fn use_modal_editing(&self) -> bool {
 2579        self.use_modal_editing
 2580    }
 2581
 2582    fn selections_did_change(
 2583        &mut self,
 2584        local: bool,
 2585        old_cursor_position: &Anchor,
 2586        show_completions: bool,
 2587        window: &mut Window,
 2588        cx: &mut Context<Self>,
 2589    ) {
 2590        window.invalidate_character_coordinates();
 2591
 2592        // Copy selections to primary selection buffer
 2593        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2594        if local {
 2595            let selections = self.selections.all::<usize>(cx);
 2596            let buffer_handle = self.buffer.read(cx).read(cx);
 2597
 2598            let mut text = String::new();
 2599            for (index, selection) in selections.iter().enumerate() {
 2600                let text_for_selection = buffer_handle
 2601                    .text_for_range(selection.start..selection.end)
 2602                    .collect::<String>();
 2603
 2604                text.push_str(&text_for_selection);
 2605                if index != selections.len() - 1 {
 2606                    text.push('\n');
 2607                }
 2608            }
 2609
 2610            if !text.is_empty() {
 2611                cx.write_to_primary(ClipboardItem::new_string(text));
 2612            }
 2613        }
 2614
 2615        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2616            self.buffer.update(cx, |buffer, cx| {
 2617                buffer.set_active_selections(
 2618                    &self.selections.disjoint_anchors(),
 2619                    self.selections.line_mode,
 2620                    self.cursor_shape,
 2621                    cx,
 2622                )
 2623            });
 2624        }
 2625        let display_map = self
 2626            .display_map
 2627            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2628        let buffer = &display_map.buffer_snapshot;
 2629        self.add_selections_state = None;
 2630        self.select_next_state = None;
 2631        self.select_prev_state = None;
 2632        self.select_syntax_node_history.try_clear();
 2633        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2634        self.snippet_stack
 2635            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2636        self.take_rename(false, window, cx);
 2637
 2638        let new_cursor_position = self.selections.newest_anchor().head();
 2639
 2640        self.push_to_nav_history(
 2641            *old_cursor_position,
 2642            Some(new_cursor_position.to_point(buffer)),
 2643            false,
 2644            cx,
 2645        );
 2646
 2647        if local {
 2648            let new_cursor_position = self.selections.newest_anchor().head();
 2649            let mut context_menu = self.context_menu.borrow_mut();
 2650            let completion_menu = match context_menu.as_ref() {
 2651                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2652                _ => {
 2653                    *context_menu = None;
 2654                    None
 2655                }
 2656            };
 2657            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2658                if !self.registered_buffers.contains_key(&buffer_id) {
 2659                    if let Some(project) = self.project.as_ref() {
 2660                        project.update(cx, |project, cx| {
 2661                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2662                                return;
 2663                            };
 2664                            self.registered_buffers.insert(
 2665                                buffer_id,
 2666                                project.register_buffer_with_language_servers(&buffer, cx),
 2667                            );
 2668                        })
 2669                    }
 2670                }
 2671            }
 2672
 2673            if let Some(completion_menu) = completion_menu {
 2674                let cursor_position = new_cursor_position.to_offset(buffer);
 2675                let (word_range, kind) =
 2676                    buffer.surrounding_word(completion_menu.initial_position, true);
 2677                if kind == Some(CharKind::Word)
 2678                    && word_range.to_inclusive().contains(&cursor_position)
 2679                {
 2680                    let mut completion_menu = completion_menu.clone();
 2681                    drop(context_menu);
 2682
 2683                    let query = Self::completion_query(buffer, cursor_position);
 2684                    cx.spawn(async move |this, cx| {
 2685                        completion_menu
 2686                            .filter(query.as_deref(), cx.background_executor().clone())
 2687                            .await;
 2688
 2689                        this.update(cx, |this, cx| {
 2690                            let mut context_menu = this.context_menu.borrow_mut();
 2691                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2692                            else {
 2693                                return;
 2694                            };
 2695
 2696                            if menu.id > completion_menu.id {
 2697                                return;
 2698                            }
 2699
 2700                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2701                            drop(context_menu);
 2702                            cx.notify();
 2703                        })
 2704                    })
 2705                    .detach();
 2706
 2707                    if show_completions {
 2708                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2709                    }
 2710                } else {
 2711                    drop(context_menu);
 2712                    self.hide_context_menu(window, cx);
 2713                }
 2714            } else {
 2715                drop(context_menu);
 2716            }
 2717
 2718            hide_hover(self, cx);
 2719
 2720            if old_cursor_position.to_display_point(&display_map).row()
 2721                != new_cursor_position.to_display_point(&display_map).row()
 2722            {
 2723                self.available_code_actions.take();
 2724            }
 2725            self.refresh_code_actions(window, cx);
 2726            self.refresh_document_highlights(cx);
 2727            self.refresh_selected_text_highlights(false, window, cx);
 2728            refresh_matching_bracket_highlights(self, window, cx);
 2729            self.update_visible_inline_completion(window, cx);
 2730            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2731            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2732            self.inline_blame_popover.take();
 2733            if self.git_blame_inline_enabled {
 2734                self.start_inline_blame_timer(window, cx);
 2735            }
 2736        }
 2737
 2738        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2739        cx.emit(EditorEvent::SelectionsChanged { local });
 2740
 2741        let selections = &self.selections.disjoint;
 2742        if selections.len() == 1 {
 2743            cx.emit(SearchEvent::ActiveMatchChanged)
 2744        }
 2745        if local {
 2746            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2747                let inmemory_selections = selections
 2748                    .iter()
 2749                    .map(|s| {
 2750                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2751                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2752                    })
 2753                    .collect();
 2754                self.update_restoration_data(cx, |data| {
 2755                    data.selections = inmemory_selections;
 2756                });
 2757
 2758                if WorkspaceSettings::get(None, cx).restore_on_startup
 2759                    != RestoreOnStartupBehavior::None
 2760                {
 2761                    if let Some(workspace_id) =
 2762                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2763                    {
 2764                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2765                        let selections = selections.clone();
 2766                        let background_executor = cx.background_executor().clone();
 2767                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2768                        self.serialize_selections = cx.background_spawn(async move {
 2769                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2770                    let db_selections = selections
 2771                        .iter()
 2772                        .map(|selection| {
 2773                            (
 2774                                selection.start.to_offset(&snapshot),
 2775                                selection.end.to_offset(&snapshot),
 2776                            )
 2777                        })
 2778                        .collect();
 2779
 2780                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2781                        .await
 2782                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2783                        .log_err();
 2784                });
 2785                    }
 2786                }
 2787            }
 2788        }
 2789
 2790        cx.notify();
 2791    }
 2792
 2793    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2794        use text::ToOffset as _;
 2795        use text::ToPoint as _;
 2796
 2797        if self.mode.is_minimap()
 2798            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2799        {
 2800            return;
 2801        }
 2802
 2803        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2804            return;
 2805        };
 2806
 2807        let snapshot = singleton.read(cx).snapshot();
 2808        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2809            let display_snapshot = display_map.snapshot(cx);
 2810
 2811            display_snapshot
 2812                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2813                .map(|fold| {
 2814                    fold.range.start.text_anchor.to_point(&snapshot)
 2815                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2816                })
 2817                .collect()
 2818        });
 2819        self.update_restoration_data(cx, |data| {
 2820            data.folds = inmemory_folds;
 2821        });
 2822
 2823        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2824            return;
 2825        };
 2826        let background_executor = cx.background_executor().clone();
 2827        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2828        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2829            display_map
 2830                .snapshot(cx)
 2831                .folds_in_range(0..snapshot.len())
 2832                .map(|fold| {
 2833                    (
 2834                        fold.range.start.text_anchor.to_offset(&snapshot),
 2835                        fold.range.end.text_anchor.to_offset(&snapshot),
 2836                    )
 2837                })
 2838                .collect()
 2839        });
 2840        self.serialize_folds = cx.background_spawn(async move {
 2841            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2842            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2843                .await
 2844                .with_context(|| {
 2845                    format!(
 2846                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2847                    )
 2848                })
 2849                .log_err();
 2850        });
 2851    }
 2852
 2853    pub fn sync_selections(
 2854        &mut self,
 2855        other: Entity<Editor>,
 2856        cx: &mut Context<Self>,
 2857    ) -> gpui::Subscription {
 2858        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2859        self.selections.change_with(cx, |selections| {
 2860            selections.select_anchors(other_selections);
 2861        });
 2862
 2863        let other_subscription =
 2864            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2865                EditorEvent::SelectionsChanged { local: true } => {
 2866                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2867                    if other_selections.is_empty() {
 2868                        return;
 2869                    }
 2870                    this.selections.change_with(cx, |selections| {
 2871                        selections.select_anchors(other_selections);
 2872                    });
 2873                }
 2874                _ => {}
 2875            });
 2876
 2877        let this_subscription =
 2878            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2879                EditorEvent::SelectionsChanged { local: true } => {
 2880                    let these_selections = this.selections.disjoint.to_vec();
 2881                    if these_selections.is_empty() {
 2882                        return;
 2883                    }
 2884                    other.update(cx, |other_editor, cx| {
 2885                        other_editor.selections.change_with(cx, |selections| {
 2886                            selections.select_anchors(these_selections);
 2887                        })
 2888                    });
 2889                }
 2890                _ => {}
 2891            });
 2892
 2893        Subscription::join(other_subscription, this_subscription)
 2894    }
 2895
 2896    pub fn change_selections<R>(
 2897        &mut self,
 2898        autoscroll: Option<Autoscroll>,
 2899        window: &mut Window,
 2900        cx: &mut Context<Self>,
 2901        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2902    ) -> R {
 2903        self.change_selections_inner(autoscroll, true, window, cx, change)
 2904    }
 2905
 2906    fn change_selections_inner<R>(
 2907        &mut self,
 2908        autoscroll: Option<Autoscroll>,
 2909        request_completions: bool,
 2910        window: &mut Window,
 2911        cx: &mut Context<Self>,
 2912        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2913    ) -> R {
 2914        let old_cursor_position = self.selections.newest_anchor().head();
 2915        self.push_to_selection_history();
 2916
 2917        let (changed, result) = self.selections.change_with(cx, change);
 2918
 2919        if changed {
 2920            if let Some(autoscroll) = autoscroll {
 2921                self.request_autoscroll(autoscroll, cx);
 2922            }
 2923            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2924
 2925            if self.should_open_signature_help_automatically(
 2926                &old_cursor_position,
 2927                self.signature_help_state.backspace_pressed(),
 2928                cx,
 2929            ) {
 2930                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2931            }
 2932            self.signature_help_state.set_backspace_pressed(false);
 2933        }
 2934
 2935        result
 2936    }
 2937
 2938    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2939    where
 2940        I: IntoIterator<Item = (Range<S>, T)>,
 2941        S: ToOffset,
 2942        T: Into<Arc<str>>,
 2943    {
 2944        if self.read_only(cx) {
 2945            return;
 2946        }
 2947
 2948        self.buffer
 2949            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 2950    }
 2951
 2952    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 2953    where
 2954        I: IntoIterator<Item = (Range<S>, T)>,
 2955        S: ToOffset,
 2956        T: Into<Arc<str>>,
 2957    {
 2958        if self.read_only(cx) {
 2959            return;
 2960        }
 2961
 2962        self.buffer.update(cx, |buffer, cx| {
 2963            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 2964        });
 2965    }
 2966
 2967    pub fn edit_with_block_indent<I, S, T>(
 2968        &mut self,
 2969        edits: I,
 2970        original_indent_columns: Vec<Option<u32>>,
 2971        cx: &mut Context<Self>,
 2972    ) where
 2973        I: IntoIterator<Item = (Range<S>, T)>,
 2974        S: ToOffset,
 2975        T: Into<Arc<str>>,
 2976    {
 2977        if self.read_only(cx) {
 2978            return;
 2979        }
 2980
 2981        self.buffer.update(cx, |buffer, cx| {
 2982            buffer.edit(
 2983                edits,
 2984                Some(AutoindentMode::Block {
 2985                    original_indent_columns,
 2986                }),
 2987                cx,
 2988            )
 2989        });
 2990    }
 2991
 2992    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 2993        self.hide_context_menu(window, cx);
 2994
 2995        match phase {
 2996            SelectPhase::Begin {
 2997                position,
 2998                add,
 2999                click_count,
 3000            } => self.begin_selection(position, add, click_count, window, cx),
 3001            SelectPhase::BeginColumnar {
 3002                position,
 3003                goal_column,
 3004                reset,
 3005            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3006            SelectPhase::Extend {
 3007                position,
 3008                click_count,
 3009            } => self.extend_selection(position, click_count, window, cx),
 3010            SelectPhase::Update {
 3011                position,
 3012                goal_column,
 3013                scroll_delta,
 3014            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3015            SelectPhase::End => self.end_selection(window, cx),
 3016        }
 3017    }
 3018
 3019    fn extend_selection(
 3020        &mut self,
 3021        position: DisplayPoint,
 3022        click_count: usize,
 3023        window: &mut Window,
 3024        cx: &mut Context<Self>,
 3025    ) {
 3026        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3027        let tail = self.selections.newest::<usize>(cx).tail();
 3028        self.begin_selection(position, false, click_count, window, cx);
 3029
 3030        let position = position.to_offset(&display_map, Bias::Left);
 3031        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3032
 3033        let mut pending_selection = self
 3034            .selections
 3035            .pending_anchor()
 3036            .expect("extend_selection not called with pending selection");
 3037        if position >= tail {
 3038            pending_selection.start = tail_anchor;
 3039        } else {
 3040            pending_selection.end = tail_anchor;
 3041            pending_selection.reversed = true;
 3042        }
 3043
 3044        let mut pending_mode = self.selections.pending_mode().unwrap();
 3045        match &mut pending_mode {
 3046            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3047            _ => {}
 3048        }
 3049
 3050        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3051
 3052        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3053            s.set_pending(pending_selection, pending_mode)
 3054        });
 3055    }
 3056
 3057    fn begin_selection(
 3058        &mut self,
 3059        position: DisplayPoint,
 3060        add: bool,
 3061        click_count: usize,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        if !self.focus_handle.is_focused(window) {
 3066            self.last_focused_descendant = None;
 3067            window.focus(&self.focus_handle);
 3068        }
 3069
 3070        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3071        let buffer = &display_map.buffer_snapshot;
 3072        let position = display_map.clip_point(position, Bias::Left);
 3073
 3074        let start;
 3075        let end;
 3076        let mode;
 3077        let mut auto_scroll;
 3078        match click_count {
 3079            1 => {
 3080                start = buffer.anchor_before(position.to_point(&display_map));
 3081                end = start;
 3082                mode = SelectMode::Character;
 3083                auto_scroll = true;
 3084            }
 3085            2 => {
 3086                let range = movement::surrounding_word(&display_map, position);
 3087                start = buffer.anchor_before(range.start.to_point(&display_map));
 3088                end = buffer.anchor_before(range.end.to_point(&display_map));
 3089                mode = SelectMode::Word(start..end);
 3090                auto_scroll = true;
 3091            }
 3092            3 => {
 3093                let position = display_map
 3094                    .clip_point(position, Bias::Left)
 3095                    .to_point(&display_map);
 3096                let line_start = display_map.prev_line_boundary(position).0;
 3097                let next_line_start = buffer.clip_point(
 3098                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3099                    Bias::Left,
 3100                );
 3101                start = buffer.anchor_before(line_start);
 3102                end = buffer.anchor_before(next_line_start);
 3103                mode = SelectMode::Line(start..end);
 3104                auto_scroll = true;
 3105            }
 3106            _ => {
 3107                start = buffer.anchor_before(0);
 3108                end = buffer.anchor_before(buffer.len());
 3109                mode = SelectMode::All;
 3110                auto_scroll = false;
 3111            }
 3112        }
 3113        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3114
 3115        let point_to_delete: Option<usize> = {
 3116            let selected_points: Vec<Selection<Point>> =
 3117                self.selections.disjoint_in_range(start..end, cx);
 3118
 3119            if !add || click_count > 1 {
 3120                None
 3121            } else if !selected_points.is_empty() {
 3122                Some(selected_points[0].id)
 3123            } else {
 3124                let clicked_point_already_selected =
 3125                    self.selections.disjoint.iter().find(|selection| {
 3126                        selection.start.to_point(buffer) == start.to_point(buffer)
 3127                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3128                    });
 3129
 3130                clicked_point_already_selected.map(|selection| selection.id)
 3131            }
 3132        };
 3133
 3134        let selections_count = self.selections.count();
 3135
 3136        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3137            if let Some(point_to_delete) = point_to_delete {
 3138                s.delete(point_to_delete);
 3139
 3140                if selections_count == 1 {
 3141                    s.set_pending_anchor_range(start..end, mode);
 3142                }
 3143            } else {
 3144                if !add {
 3145                    s.clear_disjoint();
 3146                }
 3147
 3148                s.set_pending_anchor_range(start..end, mode);
 3149            }
 3150        });
 3151    }
 3152
 3153    fn begin_columnar_selection(
 3154        &mut self,
 3155        position: DisplayPoint,
 3156        goal_column: u32,
 3157        reset: bool,
 3158        window: &mut Window,
 3159        cx: &mut Context<Self>,
 3160    ) {
 3161        if !self.focus_handle.is_focused(window) {
 3162            self.last_focused_descendant = None;
 3163            window.focus(&self.focus_handle);
 3164        }
 3165
 3166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3167
 3168        if reset {
 3169            let pointer_position = display_map
 3170                .buffer_snapshot
 3171                .anchor_before(position.to_point(&display_map));
 3172
 3173            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3174                s.clear_disjoint();
 3175                s.set_pending_anchor_range(
 3176                    pointer_position..pointer_position,
 3177                    SelectMode::Character,
 3178                );
 3179            });
 3180        }
 3181
 3182        let tail = self.selections.newest::<Point>(cx).tail();
 3183        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3184
 3185        if !reset {
 3186            self.select_columns(
 3187                tail.to_display_point(&display_map),
 3188                position,
 3189                goal_column,
 3190                &display_map,
 3191                window,
 3192                cx,
 3193            );
 3194        }
 3195    }
 3196
 3197    fn update_selection(
 3198        &mut self,
 3199        position: DisplayPoint,
 3200        goal_column: u32,
 3201        scroll_delta: gpui::Point<f32>,
 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
 3207        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3208            let tail = tail.to_display_point(&display_map);
 3209            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3210        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3211            let buffer = self.buffer.read(cx).snapshot(cx);
 3212            let head;
 3213            let tail;
 3214            let mode = self.selections.pending_mode().unwrap();
 3215            match &mode {
 3216                SelectMode::Character => {
 3217                    head = position.to_point(&display_map);
 3218                    tail = pending.tail().to_point(&buffer);
 3219                }
 3220                SelectMode::Word(original_range) => {
 3221                    let original_display_range = original_range.start.to_display_point(&display_map)
 3222                        ..original_range.end.to_display_point(&display_map);
 3223                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3224                        ..original_display_range.end.to_point(&display_map);
 3225                    if movement::is_inside_word(&display_map, position)
 3226                        || original_display_range.contains(&position)
 3227                    {
 3228                        let word_range = movement::surrounding_word(&display_map, position);
 3229                        if word_range.start < original_display_range.start {
 3230                            head = word_range.start.to_point(&display_map);
 3231                        } else {
 3232                            head = word_range.end.to_point(&display_map);
 3233                        }
 3234                    } else {
 3235                        head = position.to_point(&display_map);
 3236                    }
 3237
 3238                    if head <= original_buffer_range.start {
 3239                        tail = original_buffer_range.end;
 3240                    } else {
 3241                        tail = original_buffer_range.start;
 3242                    }
 3243                }
 3244                SelectMode::Line(original_range) => {
 3245                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3246
 3247                    let position = display_map
 3248                        .clip_point(position, Bias::Left)
 3249                        .to_point(&display_map);
 3250                    let line_start = display_map.prev_line_boundary(position).0;
 3251                    let next_line_start = buffer.clip_point(
 3252                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3253                        Bias::Left,
 3254                    );
 3255
 3256                    if line_start < original_range.start {
 3257                        head = line_start
 3258                    } else {
 3259                        head = next_line_start
 3260                    }
 3261
 3262                    if head <= original_range.start {
 3263                        tail = original_range.end;
 3264                    } else {
 3265                        tail = original_range.start;
 3266                    }
 3267                }
 3268                SelectMode::All => {
 3269                    return;
 3270                }
 3271            };
 3272
 3273            if head < tail {
 3274                pending.start = buffer.anchor_before(head);
 3275                pending.end = buffer.anchor_before(tail);
 3276                pending.reversed = true;
 3277            } else {
 3278                pending.start = buffer.anchor_before(tail);
 3279                pending.end = buffer.anchor_before(head);
 3280                pending.reversed = false;
 3281            }
 3282
 3283            self.change_selections(None, window, cx, |s| {
 3284                s.set_pending(pending, mode);
 3285            });
 3286        } else {
 3287            log::error!("update_selection dispatched with no pending selection");
 3288            return;
 3289        }
 3290
 3291        self.apply_scroll_delta(scroll_delta, window, cx);
 3292        cx.notify();
 3293    }
 3294
 3295    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3296        self.columnar_selection_tail.take();
 3297        if self.selections.pending_anchor().is_some() {
 3298            let selections = self.selections.all::<usize>(cx);
 3299            self.change_selections(None, window, cx, |s| {
 3300                s.select(selections);
 3301                s.clear_pending();
 3302            });
 3303        }
 3304    }
 3305
 3306    fn select_columns(
 3307        &mut self,
 3308        tail: DisplayPoint,
 3309        head: DisplayPoint,
 3310        goal_column: u32,
 3311        display_map: &DisplaySnapshot,
 3312        window: &mut Window,
 3313        cx: &mut Context<Self>,
 3314    ) {
 3315        let start_row = cmp::min(tail.row(), head.row());
 3316        let end_row = cmp::max(tail.row(), head.row());
 3317        let start_column = cmp::min(tail.column(), goal_column);
 3318        let end_column = cmp::max(tail.column(), goal_column);
 3319        let reversed = start_column < tail.column();
 3320
 3321        let selection_ranges = (start_row.0..=end_row.0)
 3322            .map(DisplayRow)
 3323            .filter_map(|row| {
 3324                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3325                    let start = display_map
 3326                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3327                        .to_point(display_map);
 3328                    let end = display_map
 3329                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3330                        .to_point(display_map);
 3331                    if reversed {
 3332                        Some(end..start)
 3333                    } else {
 3334                        Some(start..end)
 3335                    }
 3336                } else {
 3337                    None
 3338                }
 3339            })
 3340            .collect::<Vec<_>>();
 3341
 3342        self.change_selections(None, window, cx, |s| {
 3343            s.select_ranges(selection_ranges);
 3344        });
 3345        cx.notify();
 3346    }
 3347
 3348    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3349        self.selections
 3350            .all_adjusted(cx)
 3351            .iter()
 3352            .any(|selection| !selection.is_empty())
 3353    }
 3354
 3355    pub fn has_pending_nonempty_selection(&self) -> bool {
 3356        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3357            Some(Selection { start, end, .. }) => start != end,
 3358            None => false,
 3359        };
 3360
 3361        pending_nonempty_selection
 3362            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3363    }
 3364
 3365    pub fn has_pending_selection(&self) -> bool {
 3366        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3367    }
 3368
 3369    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3370        self.selection_mark_mode = false;
 3371
 3372        if self.clear_expanded_diff_hunks(cx) {
 3373            cx.notify();
 3374            return;
 3375        }
 3376        if self.dismiss_menus_and_popups(true, window, cx) {
 3377            return;
 3378        }
 3379
 3380        if self.mode.is_full()
 3381            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3382        {
 3383            return;
 3384        }
 3385
 3386        cx.propagate();
 3387    }
 3388
 3389    pub fn dismiss_menus_and_popups(
 3390        &mut self,
 3391        is_user_requested: bool,
 3392        window: &mut Window,
 3393        cx: &mut Context<Self>,
 3394    ) -> bool {
 3395        if self.take_rename(false, window, cx).is_some() {
 3396            return true;
 3397        }
 3398
 3399        if hide_hover(self, cx) {
 3400            return true;
 3401        }
 3402
 3403        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3404            return true;
 3405        }
 3406
 3407        if self.hide_context_menu(window, cx).is_some() {
 3408            return true;
 3409        }
 3410
 3411        if self.mouse_context_menu.take().is_some() {
 3412            return true;
 3413        }
 3414
 3415        if is_user_requested && self.discard_inline_completion(true, cx) {
 3416            return true;
 3417        }
 3418
 3419        if self.snippet_stack.pop().is_some() {
 3420            return true;
 3421        }
 3422
 3423        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3424            self.dismiss_diagnostics(cx);
 3425            return true;
 3426        }
 3427
 3428        false
 3429    }
 3430
 3431    fn linked_editing_ranges_for(
 3432        &self,
 3433        selection: Range<text::Anchor>,
 3434        cx: &App,
 3435    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3436        if self.linked_edit_ranges.is_empty() {
 3437            return None;
 3438        }
 3439        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3440            selection.end.buffer_id.and_then(|end_buffer_id| {
 3441                if selection.start.buffer_id != Some(end_buffer_id) {
 3442                    return None;
 3443                }
 3444                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3445                let snapshot = buffer.read(cx).snapshot();
 3446                self.linked_edit_ranges
 3447                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3448                    .map(|ranges| (ranges, snapshot, buffer))
 3449            })?;
 3450        use text::ToOffset as TO;
 3451        // find offset from the start of current range to current cursor position
 3452        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3453
 3454        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3455        let start_difference = start_offset - start_byte_offset;
 3456        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3457        let end_difference = end_offset - start_byte_offset;
 3458        // Current range has associated linked ranges.
 3459        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3460        for range in linked_ranges.iter() {
 3461            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3462            let end_offset = start_offset + end_difference;
 3463            let start_offset = start_offset + start_difference;
 3464            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3465                continue;
 3466            }
 3467            if self.selections.disjoint_anchor_ranges().any(|s| {
 3468                if s.start.buffer_id != selection.start.buffer_id
 3469                    || s.end.buffer_id != selection.end.buffer_id
 3470                {
 3471                    return false;
 3472                }
 3473                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3474                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3475            }) {
 3476                continue;
 3477            }
 3478            let start = buffer_snapshot.anchor_after(start_offset);
 3479            let end = buffer_snapshot.anchor_after(end_offset);
 3480            linked_edits
 3481                .entry(buffer.clone())
 3482                .or_default()
 3483                .push(start..end);
 3484        }
 3485        Some(linked_edits)
 3486    }
 3487
 3488    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3489        let text: Arc<str> = text.into();
 3490
 3491        if self.read_only(cx) {
 3492            return;
 3493        }
 3494
 3495        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3496
 3497        let selections = self.selections.all_adjusted(cx);
 3498        let mut bracket_inserted = false;
 3499        let mut edits = Vec::new();
 3500        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3501        let mut new_selections = Vec::with_capacity(selections.len());
 3502        let mut new_autoclose_regions = Vec::new();
 3503        let snapshot = self.buffer.read(cx).read(cx);
 3504        let mut clear_linked_edit_ranges = false;
 3505
 3506        for (selection, autoclose_region) in
 3507            self.selections_with_autoclose_regions(selections, &snapshot)
 3508        {
 3509            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3510                // Determine if the inserted text matches the opening or closing
 3511                // bracket of any of this language's bracket pairs.
 3512                let mut bracket_pair = None;
 3513                let mut is_bracket_pair_start = false;
 3514                let mut is_bracket_pair_end = false;
 3515                if !text.is_empty() {
 3516                    let mut bracket_pair_matching_end = None;
 3517                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3518                    //  and they are removing the character that triggered IME popup.
 3519                    for (pair, enabled) in scope.brackets() {
 3520                        if !pair.close && !pair.surround {
 3521                            continue;
 3522                        }
 3523
 3524                        if enabled && pair.start.ends_with(text.as_ref()) {
 3525                            let prefix_len = pair.start.len() - text.len();
 3526                            let preceding_text_matches_prefix = prefix_len == 0
 3527                                || (selection.start.column >= (prefix_len as u32)
 3528                                    && snapshot.contains_str_at(
 3529                                        Point::new(
 3530                                            selection.start.row,
 3531                                            selection.start.column - (prefix_len as u32),
 3532                                        ),
 3533                                        &pair.start[..prefix_len],
 3534                                    ));
 3535                            if preceding_text_matches_prefix {
 3536                                bracket_pair = Some(pair.clone());
 3537                                is_bracket_pair_start = true;
 3538                                break;
 3539                            }
 3540                        }
 3541                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3542                        {
 3543                            // take first bracket pair matching end, but don't break in case a later bracket
 3544                            // pair matches start
 3545                            bracket_pair_matching_end = Some(pair.clone());
 3546                        }
 3547                    }
 3548                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3549                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3550                        is_bracket_pair_end = true;
 3551                    }
 3552                }
 3553
 3554                if let Some(bracket_pair) = bracket_pair {
 3555                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3556                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3557                    let auto_surround =
 3558                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3559                    if selection.is_empty() {
 3560                        if is_bracket_pair_start {
 3561                            // If the inserted text is a suffix of an opening bracket and the
 3562                            // selection is preceded by the rest of the opening bracket, then
 3563                            // insert the closing bracket.
 3564                            let following_text_allows_autoclose = snapshot
 3565                                .chars_at(selection.start)
 3566                                .next()
 3567                                .map_or(true, |c| scope.should_autoclose_before(c));
 3568
 3569                            let preceding_text_allows_autoclose = selection.start.column == 0
 3570                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3571                                    true,
 3572                                    |c| {
 3573                                        bracket_pair.start != bracket_pair.end
 3574                                            || !snapshot
 3575                                                .char_classifier_at(selection.start)
 3576                                                .is_word(c)
 3577                                    },
 3578                                );
 3579
 3580                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3581                                && bracket_pair.start.len() == 1
 3582                            {
 3583                                let target = bracket_pair.start.chars().next().unwrap();
 3584                                let current_line_count = snapshot
 3585                                    .reversed_chars_at(selection.start)
 3586                                    .take_while(|&c| c != '\n')
 3587                                    .filter(|&c| c == target)
 3588                                    .count();
 3589                                current_line_count % 2 == 1
 3590                            } else {
 3591                                false
 3592                            };
 3593
 3594                            if autoclose
 3595                                && bracket_pair.close
 3596                                && following_text_allows_autoclose
 3597                                && preceding_text_allows_autoclose
 3598                                && !is_closing_quote
 3599                            {
 3600                                let anchor = snapshot.anchor_before(selection.end);
 3601                                new_selections.push((selection.map(|_| anchor), text.len()));
 3602                                new_autoclose_regions.push((
 3603                                    anchor,
 3604                                    text.len(),
 3605                                    selection.id,
 3606                                    bracket_pair.clone(),
 3607                                ));
 3608                                edits.push((
 3609                                    selection.range(),
 3610                                    format!("{}{}", text, bracket_pair.end).into(),
 3611                                ));
 3612                                bracket_inserted = true;
 3613                                continue;
 3614                            }
 3615                        }
 3616
 3617                        if let Some(region) = autoclose_region {
 3618                            // If the selection is followed by an auto-inserted closing bracket,
 3619                            // then don't insert that closing bracket again; just move the selection
 3620                            // past the closing bracket.
 3621                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3622                                && text.as_ref() == region.pair.end.as_str();
 3623                            if should_skip {
 3624                                let anchor = snapshot.anchor_after(selection.end);
 3625                                new_selections
 3626                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3627                                continue;
 3628                            }
 3629                        }
 3630
 3631                        let always_treat_brackets_as_autoclosed = snapshot
 3632                            .language_settings_at(selection.start, cx)
 3633                            .always_treat_brackets_as_autoclosed;
 3634                        if always_treat_brackets_as_autoclosed
 3635                            && is_bracket_pair_end
 3636                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3637                        {
 3638                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3639                            // and the inserted text is a closing bracket and the selection is followed
 3640                            // by the closing bracket then move the selection past the closing bracket.
 3641                            let anchor = snapshot.anchor_after(selection.end);
 3642                            new_selections.push((selection.map(|_| anchor), text.len()));
 3643                            continue;
 3644                        }
 3645                    }
 3646                    // If an opening bracket is 1 character long and is typed while
 3647                    // text is selected, then surround that text with the bracket pair.
 3648                    else if auto_surround
 3649                        && bracket_pair.surround
 3650                        && is_bracket_pair_start
 3651                        && bracket_pair.start.chars().count() == 1
 3652                    {
 3653                        edits.push((selection.start..selection.start, text.clone()));
 3654                        edits.push((
 3655                            selection.end..selection.end,
 3656                            bracket_pair.end.as_str().into(),
 3657                        ));
 3658                        bracket_inserted = true;
 3659                        new_selections.push((
 3660                            Selection {
 3661                                id: selection.id,
 3662                                start: snapshot.anchor_after(selection.start),
 3663                                end: snapshot.anchor_before(selection.end),
 3664                                reversed: selection.reversed,
 3665                                goal: selection.goal,
 3666                            },
 3667                            0,
 3668                        ));
 3669                        continue;
 3670                    }
 3671                }
 3672            }
 3673
 3674            if self.auto_replace_emoji_shortcode
 3675                && selection.is_empty()
 3676                && text.as_ref().ends_with(':')
 3677            {
 3678                if let Some(possible_emoji_short_code) =
 3679                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3680                {
 3681                    if !possible_emoji_short_code.is_empty() {
 3682                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3683                            let emoji_shortcode_start = Point::new(
 3684                                selection.start.row,
 3685                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3686                            );
 3687
 3688                            // Remove shortcode from buffer
 3689                            edits.push((
 3690                                emoji_shortcode_start..selection.start,
 3691                                "".to_string().into(),
 3692                            ));
 3693                            new_selections.push((
 3694                                Selection {
 3695                                    id: selection.id,
 3696                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3697                                    end: snapshot.anchor_before(selection.start),
 3698                                    reversed: selection.reversed,
 3699                                    goal: selection.goal,
 3700                                },
 3701                                0,
 3702                            ));
 3703
 3704                            // Insert emoji
 3705                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3706                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3707                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3708
 3709                            continue;
 3710                        }
 3711                    }
 3712                }
 3713            }
 3714
 3715            // If not handling any auto-close operation, then just replace the selected
 3716            // text with the given input and move the selection to the end of the
 3717            // newly inserted text.
 3718            let anchor = snapshot.anchor_after(selection.end);
 3719            if !self.linked_edit_ranges.is_empty() {
 3720                let start_anchor = snapshot.anchor_before(selection.start);
 3721
 3722                let is_word_char = text.chars().next().map_or(true, |char| {
 3723                    let classifier = snapshot
 3724                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3725                        .ignore_punctuation(true);
 3726                    classifier.is_word(char)
 3727                });
 3728
 3729                if is_word_char {
 3730                    if let Some(ranges) = self
 3731                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3732                    {
 3733                        for (buffer, edits) in ranges {
 3734                            linked_edits
 3735                                .entry(buffer.clone())
 3736                                .or_default()
 3737                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3738                        }
 3739                    }
 3740                } else {
 3741                    clear_linked_edit_ranges = true;
 3742                }
 3743            }
 3744
 3745            new_selections.push((selection.map(|_| anchor), 0));
 3746            edits.push((selection.start..selection.end, text.clone()));
 3747        }
 3748
 3749        drop(snapshot);
 3750
 3751        self.transact(window, cx, |this, window, cx| {
 3752            if clear_linked_edit_ranges {
 3753                this.linked_edit_ranges.clear();
 3754            }
 3755            let initial_buffer_versions =
 3756                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3757
 3758            this.buffer.update(cx, |buffer, cx| {
 3759                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3760            });
 3761            for (buffer, edits) in linked_edits {
 3762                buffer.update(cx, |buffer, cx| {
 3763                    let snapshot = buffer.snapshot();
 3764                    let edits = edits
 3765                        .into_iter()
 3766                        .map(|(range, text)| {
 3767                            use text::ToPoint as TP;
 3768                            let end_point = TP::to_point(&range.end, &snapshot);
 3769                            let start_point = TP::to_point(&range.start, &snapshot);
 3770                            (start_point..end_point, text)
 3771                        })
 3772                        .sorted_by_key(|(range, _)| range.start);
 3773                    buffer.edit(edits, None, cx);
 3774                })
 3775            }
 3776            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3777            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3778            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3779            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3780                .zip(new_selection_deltas)
 3781                .map(|(selection, delta)| Selection {
 3782                    id: selection.id,
 3783                    start: selection.start + delta,
 3784                    end: selection.end + delta,
 3785                    reversed: selection.reversed,
 3786                    goal: SelectionGoal::None,
 3787                })
 3788                .collect::<Vec<_>>();
 3789
 3790            let mut i = 0;
 3791            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3792                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3793                let start = map.buffer_snapshot.anchor_before(position);
 3794                let end = map.buffer_snapshot.anchor_after(position);
 3795                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3796                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3797                        Ordering::Less => i += 1,
 3798                        Ordering::Greater => break,
 3799                        Ordering::Equal => {
 3800                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3801                                Ordering::Less => i += 1,
 3802                                Ordering::Equal => break,
 3803                                Ordering::Greater => break,
 3804                            }
 3805                        }
 3806                    }
 3807                }
 3808                this.autoclose_regions.insert(
 3809                    i,
 3810                    AutocloseRegion {
 3811                        selection_id,
 3812                        range: start..end,
 3813                        pair,
 3814                    },
 3815                );
 3816            }
 3817
 3818            let had_active_inline_completion = this.has_active_inline_completion();
 3819            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3820                s.select(new_selections)
 3821            });
 3822
 3823            if !bracket_inserted {
 3824                if let Some(on_type_format_task) =
 3825                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3826                {
 3827                    on_type_format_task.detach_and_log_err(cx);
 3828                }
 3829            }
 3830
 3831            let editor_settings = EditorSettings::get_global(cx);
 3832            if bracket_inserted
 3833                && (editor_settings.auto_signature_help
 3834                    || editor_settings.show_signature_help_after_edits)
 3835            {
 3836                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3837            }
 3838
 3839            let trigger_in_words =
 3840                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3841            if this.hard_wrap.is_some() {
 3842                let latest: Range<Point> = this.selections.newest(cx).range();
 3843                if latest.is_empty()
 3844                    && this
 3845                        .buffer()
 3846                        .read(cx)
 3847                        .snapshot(cx)
 3848                        .line_len(MultiBufferRow(latest.start.row))
 3849                        == latest.start.column
 3850                {
 3851                    this.rewrap_impl(
 3852                        RewrapOptions {
 3853                            override_language_settings: true,
 3854                            preserve_existing_whitespace: true,
 3855                        },
 3856                        cx,
 3857                    )
 3858                }
 3859            }
 3860            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3861            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3862            this.refresh_inline_completion(true, false, window, cx);
 3863            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3864        });
 3865    }
 3866
 3867    fn find_possible_emoji_shortcode_at_position(
 3868        snapshot: &MultiBufferSnapshot,
 3869        position: Point,
 3870    ) -> Option<String> {
 3871        let mut chars = Vec::new();
 3872        let mut found_colon = false;
 3873        for char in snapshot.reversed_chars_at(position).take(100) {
 3874            // Found a possible emoji shortcode in the middle of the buffer
 3875            if found_colon {
 3876                if char.is_whitespace() {
 3877                    chars.reverse();
 3878                    return Some(chars.iter().collect());
 3879                }
 3880                // If the previous character is not a whitespace, we are in the middle of a word
 3881                // and we only want to complete the shortcode if the word is made up of other emojis
 3882                let mut containing_word = String::new();
 3883                for ch in snapshot
 3884                    .reversed_chars_at(position)
 3885                    .skip(chars.len() + 1)
 3886                    .take(100)
 3887                {
 3888                    if ch.is_whitespace() {
 3889                        break;
 3890                    }
 3891                    containing_word.push(ch);
 3892                }
 3893                let containing_word = containing_word.chars().rev().collect::<String>();
 3894                if util::word_consists_of_emojis(containing_word.as_str()) {
 3895                    chars.reverse();
 3896                    return Some(chars.iter().collect());
 3897                }
 3898            }
 3899
 3900            if char.is_whitespace() || !char.is_ascii() {
 3901                return None;
 3902            }
 3903            if char == ':' {
 3904                found_colon = true;
 3905            } else {
 3906                chars.push(char);
 3907            }
 3908        }
 3909        // Found a possible emoji shortcode at the beginning of the buffer
 3910        chars.reverse();
 3911        Some(chars.iter().collect())
 3912    }
 3913
 3914    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3916        self.transact(window, cx, |this, window, cx| {
 3917            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3918                let selections = this.selections.all::<usize>(cx);
 3919                let multi_buffer = this.buffer.read(cx);
 3920                let buffer = multi_buffer.snapshot(cx);
 3921                selections
 3922                    .iter()
 3923                    .map(|selection| {
 3924                        let start_point = selection.start.to_point(&buffer);
 3925                        let mut existing_indent =
 3926                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3927                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3928                        let start = selection.start;
 3929                        let end = selection.end;
 3930                        let selection_is_empty = start == end;
 3931                        let language_scope = buffer.language_scope_at(start);
 3932                        let (
 3933                            comment_delimiter,
 3934                            doc_delimiter,
 3935                            insert_extra_newline,
 3936                            indent_on_newline,
 3937                            indent_on_extra_newline,
 3938                        ) = if let Some(language) = &language_scope {
 3939                            let mut insert_extra_newline =
 3940                                insert_extra_newline_brackets(&buffer, start..end, language)
 3941                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 3942
 3943                            // Comment extension on newline is allowed only for cursor selections
 3944                            let comment_delimiter = maybe!({
 3945                                if !selection_is_empty {
 3946                                    return None;
 3947                                }
 3948
 3949                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3950                                    return None;
 3951                                }
 3952
 3953                                let delimiters = language.line_comment_prefixes();
 3954                                let max_len_of_delimiter =
 3955                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 3956                                let (snapshot, range) =
 3957                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 3958
 3959                                let num_of_whitespaces = snapshot
 3960                                    .chars_for_range(range.clone())
 3961                                    .take_while(|c| c.is_whitespace())
 3962                                    .count();
 3963                                let comment_candidate = snapshot
 3964                                    .chars_for_range(range)
 3965                                    .skip(num_of_whitespaces)
 3966                                    .take(max_len_of_delimiter)
 3967                                    .collect::<String>();
 3968                                let (delimiter, trimmed_len) = delimiters
 3969                                    .iter()
 3970                                    .filter_map(|delimiter| {
 3971                                        let prefix = delimiter.trim_end();
 3972                                        if comment_candidate.starts_with(prefix) {
 3973                                            Some((delimiter, prefix.len()))
 3974                                        } else {
 3975                                            None
 3976                                        }
 3977                                    })
 3978                                    .max_by_key(|(_, len)| *len)?;
 3979
 3980                                let cursor_is_placed_after_comment_marker =
 3981                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 3982                                if cursor_is_placed_after_comment_marker {
 3983                                    Some(delimiter.clone())
 3984                                } else {
 3985                                    None
 3986                                }
 3987                            });
 3988
 3989                            let mut indent_on_newline = IndentSize::spaces(0);
 3990                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 3991
 3992                            let doc_delimiter = maybe!({
 3993                                if !selection_is_empty {
 3994                                    return None;
 3995                                }
 3996
 3997                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 3998                                    return None;
 3999                                }
 4000
 4001                                let DocumentationConfig {
 4002                                    start: start_tag,
 4003                                    end: end_tag,
 4004                                    prefix: delimiter,
 4005                                    tab_size: len,
 4006                                } = language.documentation()?;
 4007
 4008                                let (snapshot, range) =
 4009                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4010
 4011                                let num_of_whitespaces = snapshot
 4012                                    .chars_for_range(range.clone())
 4013                                    .take_while(|c| c.is_whitespace())
 4014                                    .count();
 4015
 4016                                let cursor_is_after_start_tag = {
 4017                                    let start_tag_len = start_tag.len();
 4018                                    let start_tag_line = snapshot
 4019                                        .chars_for_range(range.clone())
 4020                                        .skip(num_of_whitespaces)
 4021                                        .take(start_tag_len)
 4022                                        .collect::<String>();
 4023                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4024                                        num_of_whitespaces + start_tag_len
 4025                                            <= start_point.column as usize
 4026                                    } else {
 4027                                        false
 4028                                    }
 4029                                };
 4030
 4031                                let cursor_is_after_delimiter = {
 4032                                    let delimiter_trim = delimiter.trim_end();
 4033                                    let delimiter_line = snapshot
 4034                                        .chars_for_range(range.clone())
 4035                                        .skip(num_of_whitespaces)
 4036                                        .take(delimiter_trim.len())
 4037                                        .collect::<String>();
 4038                                    if delimiter_line.starts_with(delimiter_trim) {
 4039                                        num_of_whitespaces + delimiter_trim.len()
 4040                                            <= start_point.column as usize
 4041                                    } else {
 4042                                        false
 4043                                    }
 4044                                };
 4045
 4046                                let cursor_is_before_end_tag_if_exists = {
 4047                                    let mut char_position = 0u32;
 4048                                    let mut end_tag_offset = None;
 4049
 4050                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4051                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4052                                            let chars_before_match =
 4053                                                chunk[..byte_pos].chars().count() as u32;
 4054                                            end_tag_offset =
 4055                                                Some(char_position + chars_before_match);
 4056                                            break 'outer;
 4057                                        }
 4058                                        char_position += chunk.chars().count() as u32;
 4059                                    }
 4060
 4061                                    if let Some(end_tag_offset) = end_tag_offset {
 4062                                        let cursor_is_before_end_tag =
 4063                                            start_point.column <= end_tag_offset;
 4064                                        if cursor_is_after_start_tag {
 4065                                            if cursor_is_before_end_tag {
 4066                                                insert_extra_newline = true;
 4067                                            }
 4068                                            let cursor_is_at_start_of_end_tag =
 4069                                                start_point.column == end_tag_offset;
 4070                                            if cursor_is_at_start_of_end_tag {
 4071                                                indent_on_extra_newline.len = (*len).into();
 4072                                            }
 4073                                        }
 4074                                        cursor_is_before_end_tag
 4075                                    } else {
 4076                                        true
 4077                                    }
 4078                                };
 4079
 4080                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4081                                    && cursor_is_before_end_tag_if_exists
 4082                                {
 4083                                    if cursor_is_after_start_tag {
 4084                                        indent_on_newline.len = (*len).into();
 4085                                    }
 4086                                    Some(delimiter.clone())
 4087                                } else {
 4088                                    None
 4089                                }
 4090                            });
 4091
 4092                            (
 4093                                comment_delimiter,
 4094                                doc_delimiter,
 4095                                insert_extra_newline,
 4096                                indent_on_newline,
 4097                                indent_on_extra_newline,
 4098                            )
 4099                        } else {
 4100                            (
 4101                                None,
 4102                                None,
 4103                                false,
 4104                                IndentSize::default(),
 4105                                IndentSize::default(),
 4106                            )
 4107                        };
 4108
 4109                        let prevent_auto_indent = doc_delimiter.is_some();
 4110                        let delimiter = comment_delimiter.or(doc_delimiter);
 4111
 4112                        let capacity_for_delimiter =
 4113                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4114                        let mut new_text = String::with_capacity(
 4115                            1 + capacity_for_delimiter
 4116                                + existing_indent.len as usize
 4117                                + indent_on_newline.len as usize
 4118                                + indent_on_extra_newline.len as usize,
 4119                        );
 4120                        new_text.push('\n');
 4121                        new_text.extend(existing_indent.chars());
 4122                        new_text.extend(indent_on_newline.chars());
 4123
 4124                        if let Some(delimiter) = &delimiter {
 4125                            new_text.push_str(delimiter);
 4126                        }
 4127
 4128                        if insert_extra_newline {
 4129                            new_text.push('\n');
 4130                            new_text.extend(existing_indent.chars());
 4131                            new_text.extend(indent_on_extra_newline.chars());
 4132                        }
 4133
 4134                        let anchor = buffer.anchor_after(end);
 4135                        let new_selection = selection.map(|_| anchor);
 4136                        (
 4137                            ((start..end, new_text), prevent_auto_indent),
 4138                            (insert_extra_newline, new_selection),
 4139                        )
 4140                    })
 4141                    .unzip()
 4142            };
 4143
 4144            let mut auto_indent_edits = Vec::new();
 4145            let mut edits = Vec::new();
 4146            for (edit, prevent_auto_indent) in edits_with_flags {
 4147                if prevent_auto_indent {
 4148                    edits.push(edit);
 4149                } else {
 4150                    auto_indent_edits.push(edit);
 4151                }
 4152            }
 4153            if !edits.is_empty() {
 4154                this.edit(edits, cx);
 4155            }
 4156            if !auto_indent_edits.is_empty() {
 4157                this.edit_with_autoindent(auto_indent_edits, cx);
 4158            }
 4159
 4160            let buffer = this.buffer.read(cx).snapshot(cx);
 4161            let new_selections = selection_info
 4162                .into_iter()
 4163                .map(|(extra_newline_inserted, new_selection)| {
 4164                    let mut cursor = new_selection.end.to_point(&buffer);
 4165                    if extra_newline_inserted {
 4166                        cursor.row -= 1;
 4167                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4168                    }
 4169                    new_selection.map(|_| cursor)
 4170                })
 4171                .collect();
 4172
 4173            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4174                s.select(new_selections)
 4175            });
 4176            this.refresh_inline_completion(true, false, window, cx);
 4177        });
 4178    }
 4179
 4180    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4181        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4182
 4183        let buffer = self.buffer.read(cx);
 4184        let snapshot = buffer.snapshot(cx);
 4185
 4186        let mut edits = Vec::new();
 4187        let mut rows = Vec::new();
 4188
 4189        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4190            let cursor = selection.head();
 4191            let row = cursor.row;
 4192
 4193            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4194
 4195            let newline = "\n".to_string();
 4196            edits.push((start_of_line..start_of_line, newline));
 4197
 4198            rows.push(row + rows_inserted as u32);
 4199        }
 4200
 4201        self.transact(window, cx, |editor, window, cx| {
 4202            editor.edit(edits, cx);
 4203
 4204            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4205                let mut index = 0;
 4206                s.move_cursors_with(|map, _, _| {
 4207                    let row = rows[index];
 4208                    index += 1;
 4209
 4210                    let point = Point::new(row, 0);
 4211                    let boundary = map.next_line_boundary(point).1;
 4212                    let clipped = map.clip_point(boundary, Bias::Left);
 4213
 4214                    (clipped, SelectionGoal::None)
 4215                });
 4216            });
 4217
 4218            let mut indent_edits = Vec::new();
 4219            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4220            for row in rows {
 4221                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4222                for (row, indent) in indents {
 4223                    if indent.len == 0 {
 4224                        continue;
 4225                    }
 4226
 4227                    let text = match indent.kind {
 4228                        IndentKind::Space => " ".repeat(indent.len as usize),
 4229                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4230                    };
 4231                    let point = Point::new(row.0, 0);
 4232                    indent_edits.push((point..point, text));
 4233                }
 4234            }
 4235            editor.edit(indent_edits, cx);
 4236        });
 4237    }
 4238
 4239    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4240        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4241
 4242        let buffer = self.buffer.read(cx);
 4243        let snapshot = buffer.snapshot(cx);
 4244
 4245        let mut edits = Vec::new();
 4246        let mut rows = Vec::new();
 4247        let mut rows_inserted = 0;
 4248
 4249        for selection in self.selections.all_adjusted(cx) {
 4250            let cursor = selection.head();
 4251            let row = cursor.row;
 4252
 4253            let point = Point::new(row + 1, 0);
 4254            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4255
 4256            let newline = "\n".to_string();
 4257            edits.push((start_of_line..start_of_line, newline));
 4258
 4259            rows_inserted += 1;
 4260            rows.push(row + rows_inserted);
 4261        }
 4262
 4263        self.transact(window, cx, |editor, window, cx| {
 4264            editor.edit(edits, cx);
 4265
 4266            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4267                let mut index = 0;
 4268                s.move_cursors_with(|map, _, _| {
 4269                    let row = rows[index];
 4270                    index += 1;
 4271
 4272                    let point = Point::new(row, 0);
 4273                    let boundary = map.next_line_boundary(point).1;
 4274                    let clipped = map.clip_point(boundary, Bias::Left);
 4275
 4276                    (clipped, SelectionGoal::None)
 4277                });
 4278            });
 4279
 4280            let mut indent_edits = Vec::new();
 4281            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4282            for row in rows {
 4283                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4284                for (row, indent) in indents {
 4285                    if indent.len == 0 {
 4286                        continue;
 4287                    }
 4288
 4289                    let text = match indent.kind {
 4290                        IndentKind::Space => " ".repeat(indent.len as usize),
 4291                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4292                    };
 4293                    let point = Point::new(row.0, 0);
 4294                    indent_edits.push((point..point, text));
 4295                }
 4296            }
 4297            editor.edit(indent_edits, cx);
 4298        });
 4299    }
 4300
 4301    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4302        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4303            original_indent_columns: Vec::new(),
 4304        });
 4305        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4306    }
 4307
 4308    fn insert_with_autoindent_mode(
 4309        &mut self,
 4310        text: &str,
 4311        autoindent_mode: Option<AutoindentMode>,
 4312        window: &mut Window,
 4313        cx: &mut Context<Self>,
 4314    ) {
 4315        if self.read_only(cx) {
 4316            return;
 4317        }
 4318
 4319        let text: Arc<str> = text.into();
 4320        self.transact(window, cx, |this, window, cx| {
 4321            let old_selections = this.selections.all_adjusted(cx);
 4322            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4323                let anchors = {
 4324                    let snapshot = buffer.read(cx);
 4325                    old_selections
 4326                        .iter()
 4327                        .map(|s| {
 4328                            let anchor = snapshot.anchor_after(s.head());
 4329                            s.map(|_| anchor)
 4330                        })
 4331                        .collect::<Vec<_>>()
 4332                };
 4333                buffer.edit(
 4334                    old_selections
 4335                        .iter()
 4336                        .map(|s| (s.start..s.end, text.clone())),
 4337                    autoindent_mode,
 4338                    cx,
 4339                );
 4340                anchors
 4341            });
 4342
 4343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4344                s.select_anchors(selection_anchors);
 4345            });
 4346
 4347            cx.notify();
 4348        });
 4349    }
 4350
 4351    fn trigger_completion_on_input(
 4352        &mut self,
 4353        text: &str,
 4354        trigger_in_words: bool,
 4355        window: &mut Window,
 4356        cx: &mut Context<Self>,
 4357    ) {
 4358        let ignore_completion_provider = self
 4359            .context_menu
 4360            .borrow()
 4361            .as_ref()
 4362            .map(|menu| match menu {
 4363                CodeContextMenu::Completions(completions_menu) => {
 4364                    completions_menu.ignore_completion_provider
 4365                }
 4366                CodeContextMenu::CodeActions(_) => false,
 4367            })
 4368            .unwrap_or(false);
 4369
 4370        if ignore_completion_provider {
 4371            self.show_word_completions(&ShowWordCompletions, window, cx);
 4372        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4373            self.show_completions(
 4374                &ShowCompletions {
 4375                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4376                },
 4377                window,
 4378                cx,
 4379            );
 4380        } else {
 4381            self.hide_context_menu(window, cx);
 4382        }
 4383    }
 4384
 4385    fn is_completion_trigger(
 4386        &self,
 4387        text: &str,
 4388        trigger_in_words: bool,
 4389        cx: &mut Context<Self>,
 4390    ) -> bool {
 4391        let position = self.selections.newest_anchor().head();
 4392        let multibuffer = self.buffer.read(cx);
 4393        let Some(buffer) = position
 4394            .buffer_id
 4395            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4396        else {
 4397            return false;
 4398        };
 4399
 4400        if let Some(completion_provider) = &self.completion_provider {
 4401            completion_provider.is_completion_trigger(
 4402                &buffer,
 4403                position.text_anchor,
 4404                text,
 4405                trigger_in_words,
 4406                cx,
 4407            )
 4408        } else {
 4409            false
 4410        }
 4411    }
 4412
 4413    /// If any empty selections is touching the start of its innermost containing autoclose
 4414    /// region, expand it to select the brackets.
 4415    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4416        let selections = self.selections.all::<usize>(cx);
 4417        let buffer = self.buffer.read(cx).read(cx);
 4418        let new_selections = self
 4419            .selections_with_autoclose_regions(selections, &buffer)
 4420            .map(|(mut selection, region)| {
 4421                if !selection.is_empty() {
 4422                    return selection;
 4423                }
 4424
 4425                if let Some(region) = region {
 4426                    let mut range = region.range.to_offset(&buffer);
 4427                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4428                        range.start -= region.pair.start.len();
 4429                        if buffer.contains_str_at(range.start, &region.pair.start)
 4430                            && buffer.contains_str_at(range.end, &region.pair.end)
 4431                        {
 4432                            range.end += region.pair.end.len();
 4433                            selection.start = range.start;
 4434                            selection.end = range.end;
 4435
 4436                            return selection;
 4437                        }
 4438                    }
 4439                }
 4440
 4441                let always_treat_brackets_as_autoclosed = buffer
 4442                    .language_settings_at(selection.start, cx)
 4443                    .always_treat_brackets_as_autoclosed;
 4444
 4445                if !always_treat_brackets_as_autoclosed {
 4446                    return selection;
 4447                }
 4448
 4449                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4450                    for (pair, enabled) in scope.brackets() {
 4451                        if !enabled || !pair.close {
 4452                            continue;
 4453                        }
 4454
 4455                        if buffer.contains_str_at(selection.start, &pair.end) {
 4456                            let pair_start_len = pair.start.len();
 4457                            if buffer.contains_str_at(
 4458                                selection.start.saturating_sub(pair_start_len),
 4459                                &pair.start,
 4460                            ) {
 4461                                selection.start -= pair_start_len;
 4462                                selection.end += pair.end.len();
 4463
 4464                                return selection;
 4465                            }
 4466                        }
 4467                    }
 4468                }
 4469
 4470                selection
 4471            })
 4472            .collect();
 4473
 4474        drop(buffer);
 4475        self.change_selections(None, window, cx, |selections| {
 4476            selections.select(new_selections)
 4477        });
 4478    }
 4479
 4480    /// Iterate the given selections, and for each one, find the smallest surrounding
 4481    /// autoclose region. This uses the ordering of the selections and the autoclose
 4482    /// regions to avoid repeated comparisons.
 4483    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4484        &'a self,
 4485        selections: impl IntoIterator<Item = Selection<D>>,
 4486        buffer: &'a MultiBufferSnapshot,
 4487    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4488        let mut i = 0;
 4489        let mut regions = self.autoclose_regions.as_slice();
 4490        selections.into_iter().map(move |selection| {
 4491            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4492
 4493            let mut enclosing = None;
 4494            while let Some(pair_state) = regions.get(i) {
 4495                if pair_state.range.end.to_offset(buffer) < range.start {
 4496                    regions = &regions[i + 1..];
 4497                    i = 0;
 4498                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4499                    break;
 4500                } else {
 4501                    if pair_state.selection_id == selection.id {
 4502                        enclosing = Some(pair_state);
 4503                    }
 4504                    i += 1;
 4505                }
 4506            }
 4507
 4508            (selection, enclosing)
 4509        })
 4510    }
 4511
 4512    /// Remove any autoclose regions that no longer contain their selection.
 4513    fn invalidate_autoclose_regions(
 4514        &mut self,
 4515        mut selections: &[Selection<Anchor>],
 4516        buffer: &MultiBufferSnapshot,
 4517    ) {
 4518        self.autoclose_regions.retain(|state| {
 4519            let mut i = 0;
 4520            while let Some(selection) = selections.get(i) {
 4521                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4522                    selections = &selections[1..];
 4523                    continue;
 4524                }
 4525                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4526                    break;
 4527                }
 4528                if selection.id == state.selection_id {
 4529                    return true;
 4530                } else {
 4531                    i += 1;
 4532                }
 4533            }
 4534            false
 4535        });
 4536    }
 4537
 4538    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4539        let offset = position.to_offset(buffer);
 4540        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4541        if offset > word_range.start && kind == Some(CharKind::Word) {
 4542            Some(
 4543                buffer
 4544                    .text_for_range(word_range.start..offset)
 4545                    .collect::<String>(),
 4546            )
 4547        } else {
 4548            None
 4549        }
 4550    }
 4551
 4552    pub fn toggle_inline_values(
 4553        &mut self,
 4554        _: &ToggleInlineValues,
 4555        _: &mut Window,
 4556        cx: &mut Context<Self>,
 4557    ) {
 4558        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4559
 4560        self.refresh_inline_values(cx);
 4561    }
 4562
 4563    pub fn toggle_inlay_hints(
 4564        &mut self,
 4565        _: &ToggleInlayHints,
 4566        _: &mut Window,
 4567        cx: &mut Context<Self>,
 4568    ) {
 4569        self.refresh_inlay_hints(
 4570            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4571            cx,
 4572        );
 4573    }
 4574
 4575    pub fn inlay_hints_enabled(&self) -> bool {
 4576        self.inlay_hint_cache.enabled
 4577    }
 4578
 4579    pub fn inline_values_enabled(&self) -> bool {
 4580        self.inline_value_cache.enabled
 4581    }
 4582
 4583    #[cfg(any(test, feature = "test-support"))]
 4584    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4585        self.display_map
 4586            .read(cx)
 4587            .current_inlays()
 4588            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4589            .cloned()
 4590            .collect()
 4591    }
 4592
 4593    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4594        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4595            return;
 4596        }
 4597
 4598        let reason_description = reason.description();
 4599        let ignore_debounce = matches!(
 4600            reason,
 4601            InlayHintRefreshReason::SettingsChange(_)
 4602                | InlayHintRefreshReason::Toggle(_)
 4603                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4604                | InlayHintRefreshReason::ModifiersChanged(_)
 4605        );
 4606        let (invalidate_cache, required_languages) = match reason {
 4607            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4608                match self.inlay_hint_cache.modifiers_override(enabled) {
 4609                    Some(enabled) => {
 4610                        if enabled {
 4611                            (InvalidationStrategy::RefreshRequested, None)
 4612                        } else {
 4613                            self.splice_inlays(
 4614                                &self
 4615                                    .visible_inlay_hints(cx)
 4616                                    .iter()
 4617                                    .map(|inlay| inlay.id)
 4618                                    .collect::<Vec<InlayId>>(),
 4619                                Vec::new(),
 4620                                cx,
 4621                            );
 4622                            return;
 4623                        }
 4624                    }
 4625                    None => return,
 4626                }
 4627            }
 4628            InlayHintRefreshReason::Toggle(enabled) => {
 4629                if self.inlay_hint_cache.toggle(enabled) {
 4630                    if enabled {
 4631                        (InvalidationStrategy::RefreshRequested, None)
 4632                    } else {
 4633                        self.splice_inlays(
 4634                            &self
 4635                                .visible_inlay_hints(cx)
 4636                                .iter()
 4637                                .map(|inlay| inlay.id)
 4638                                .collect::<Vec<InlayId>>(),
 4639                            Vec::new(),
 4640                            cx,
 4641                        );
 4642                        return;
 4643                    }
 4644                } else {
 4645                    return;
 4646                }
 4647            }
 4648            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4649                match self.inlay_hint_cache.update_settings(
 4650                    &self.buffer,
 4651                    new_settings,
 4652                    self.visible_inlay_hints(cx),
 4653                    cx,
 4654                ) {
 4655                    ControlFlow::Break(Some(InlaySplice {
 4656                        to_remove,
 4657                        to_insert,
 4658                    })) => {
 4659                        self.splice_inlays(&to_remove, to_insert, cx);
 4660                        return;
 4661                    }
 4662                    ControlFlow::Break(None) => return,
 4663                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4664                }
 4665            }
 4666            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4667                if let Some(InlaySplice {
 4668                    to_remove,
 4669                    to_insert,
 4670                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4671                {
 4672                    self.splice_inlays(&to_remove, to_insert, cx);
 4673                }
 4674                self.display_map.update(cx, |display_map, _| {
 4675                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4676                });
 4677                return;
 4678            }
 4679            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4680            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4681                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4682            }
 4683            InlayHintRefreshReason::RefreshRequested => {
 4684                (InvalidationStrategy::RefreshRequested, None)
 4685            }
 4686        };
 4687
 4688        if let Some(InlaySplice {
 4689            to_remove,
 4690            to_insert,
 4691        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4692            reason_description,
 4693            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4694            invalidate_cache,
 4695            ignore_debounce,
 4696            cx,
 4697        ) {
 4698            self.splice_inlays(&to_remove, to_insert, cx);
 4699        }
 4700    }
 4701
 4702    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4703        self.display_map
 4704            .read(cx)
 4705            .current_inlays()
 4706            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4707            .cloned()
 4708            .collect()
 4709    }
 4710
 4711    pub fn excerpts_for_inlay_hints_query(
 4712        &self,
 4713        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4714        cx: &mut Context<Editor>,
 4715    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4716        let Some(project) = self.project.as_ref() else {
 4717            return HashMap::default();
 4718        };
 4719        let project = project.read(cx);
 4720        let multi_buffer = self.buffer().read(cx);
 4721        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4722        let multi_buffer_visible_start = self
 4723            .scroll_manager
 4724            .anchor()
 4725            .anchor
 4726            .to_point(&multi_buffer_snapshot);
 4727        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4728            multi_buffer_visible_start
 4729                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4730            Bias::Left,
 4731        );
 4732        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4733        multi_buffer_snapshot
 4734            .range_to_buffer_ranges(multi_buffer_visible_range)
 4735            .into_iter()
 4736            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4737            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4738                let buffer_file = project::File::from_dyn(buffer.file())?;
 4739                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4740                let worktree_entry = buffer_worktree
 4741                    .read(cx)
 4742                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4743                if worktree_entry.is_ignored {
 4744                    return None;
 4745                }
 4746
 4747                let language = buffer.language()?;
 4748                if let Some(restrict_to_languages) = restrict_to_languages {
 4749                    if !restrict_to_languages.contains(language) {
 4750                        return None;
 4751                    }
 4752                }
 4753                Some((
 4754                    excerpt_id,
 4755                    (
 4756                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4757                        buffer.version().clone(),
 4758                        excerpt_visible_range,
 4759                    ),
 4760                ))
 4761            })
 4762            .collect()
 4763    }
 4764
 4765    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4766        TextLayoutDetails {
 4767            text_system: window.text_system().clone(),
 4768            editor_style: self.style.clone().unwrap(),
 4769            rem_size: window.rem_size(),
 4770            scroll_anchor: self.scroll_manager.anchor(),
 4771            visible_rows: self.visible_line_count(),
 4772            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4773        }
 4774    }
 4775
 4776    pub fn splice_inlays(
 4777        &self,
 4778        to_remove: &[InlayId],
 4779        to_insert: Vec<Inlay>,
 4780        cx: &mut Context<Self>,
 4781    ) {
 4782        self.display_map.update(cx, |display_map, cx| {
 4783            display_map.splice_inlays(to_remove, to_insert, cx)
 4784        });
 4785        cx.notify();
 4786    }
 4787
 4788    fn trigger_on_type_formatting(
 4789        &self,
 4790        input: String,
 4791        window: &mut Window,
 4792        cx: &mut Context<Self>,
 4793    ) -> Option<Task<Result<()>>> {
 4794        if input.len() != 1 {
 4795            return None;
 4796        }
 4797
 4798        let project = self.project.as_ref()?;
 4799        let position = self.selections.newest_anchor().head();
 4800        let (buffer, buffer_position) = self
 4801            .buffer
 4802            .read(cx)
 4803            .text_anchor_for_position(position, cx)?;
 4804
 4805        let settings = language_settings::language_settings(
 4806            buffer
 4807                .read(cx)
 4808                .language_at(buffer_position)
 4809                .map(|l| l.name()),
 4810            buffer.read(cx).file(),
 4811            cx,
 4812        );
 4813        if !settings.use_on_type_format {
 4814            return None;
 4815        }
 4816
 4817        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4818        // hence we do LSP request & edit on host side only — add formats to host's history.
 4819        let push_to_lsp_host_history = true;
 4820        // If this is not the host, append its history with new edits.
 4821        let push_to_client_history = project.read(cx).is_via_collab();
 4822
 4823        let on_type_formatting = project.update(cx, |project, cx| {
 4824            project.on_type_format(
 4825                buffer.clone(),
 4826                buffer_position,
 4827                input,
 4828                push_to_lsp_host_history,
 4829                cx,
 4830            )
 4831        });
 4832        Some(cx.spawn_in(window, async move |editor, cx| {
 4833            if let Some(transaction) = on_type_formatting.await? {
 4834                if push_to_client_history {
 4835                    buffer
 4836                        .update(cx, |buffer, _| {
 4837                            buffer.push_transaction(transaction, Instant::now());
 4838                            buffer.finalize_last_transaction();
 4839                        })
 4840                        .ok();
 4841                }
 4842                editor.update(cx, |editor, cx| {
 4843                    editor.refresh_document_highlights(cx);
 4844                })?;
 4845            }
 4846            Ok(())
 4847        }))
 4848    }
 4849
 4850    pub fn show_word_completions(
 4851        &mut self,
 4852        _: &ShowWordCompletions,
 4853        window: &mut Window,
 4854        cx: &mut Context<Self>,
 4855    ) {
 4856        self.open_completions_menu(true, None, window, cx);
 4857    }
 4858
 4859    pub fn show_completions(
 4860        &mut self,
 4861        options: &ShowCompletions,
 4862        window: &mut Window,
 4863        cx: &mut Context<Self>,
 4864    ) {
 4865        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4866    }
 4867
 4868    fn open_completions_menu(
 4869        &mut self,
 4870        ignore_completion_provider: bool,
 4871        trigger: Option<&str>,
 4872        window: &mut Window,
 4873        cx: &mut Context<Self>,
 4874    ) {
 4875        if self.pending_rename.is_some() {
 4876            return;
 4877        }
 4878        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4879            return;
 4880        }
 4881
 4882        let position = self.selections.newest_anchor().head();
 4883        if position.diff_base_anchor.is_some() {
 4884            return;
 4885        }
 4886        let (buffer, buffer_position) =
 4887            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4888                output
 4889            } else {
 4890                return;
 4891            };
 4892        let buffer_snapshot = buffer.read(cx).snapshot();
 4893        let show_completion_documentation = buffer_snapshot
 4894            .settings_at(buffer_position, cx)
 4895            .show_completion_documentation;
 4896
 4897        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4898
 4899        let trigger_kind = match trigger {
 4900            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4901                CompletionTriggerKind::TRIGGER_CHARACTER
 4902            }
 4903            _ => CompletionTriggerKind::INVOKED,
 4904        };
 4905        let completion_context = CompletionContext {
 4906            trigger_character: trigger.and_then(|trigger| {
 4907                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4908                    Some(String::from(trigger))
 4909                } else {
 4910                    None
 4911                }
 4912            }),
 4913            trigger_kind,
 4914        };
 4915
 4916        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4917        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4918            let word_to_exclude = buffer_snapshot
 4919                .text_for_range(old_range.clone())
 4920                .collect::<String>();
 4921            (
 4922                buffer_snapshot.anchor_before(old_range.start)
 4923                    ..buffer_snapshot.anchor_after(old_range.end),
 4924                Some(word_to_exclude),
 4925            )
 4926        } else {
 4927            (buffer_position..buffer_position, None)
 4928        };
 4929
 4930        let completion_settings = language_settings(
 4931            buffer_snapshot
 4932                .language_at(buffer_position)
 4933                .map(|language| language.name()),
 4934            buffer_snapshot.file(),
 4935            cx,
 4936        )
 4937        .completions;
 4938
 4939        // The document can be large, so stay in reasonable bounds when searching for words,
 4940        // otherwise completion pop-up might be slow to appear.
 4941        const WORD_LOOKUP_ROWS: u32 = 5_000;
 4942        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 4943        let min_word_search = buffer_snapshot.clip_point(
 4944            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 4945            Bias::Left,
 4946        );
 4947        let max_word_search = buffer_snapshot.clip_point(
 4948            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 4949            Bias::Right,
 4950        );
 4951        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 4952            ..buffer_snapshot.point_to_offset(max_word_search);
 4953
 4954        let provider = self
 4955            .completion_provider
 4956            .as_ref()
 4957            .filter(|_| !ignore_completion_provider);
 4958        let skip_digits = query
 4959            .as_ref()
 4960            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 4961
 4962        let (mut words, provided_completions) = match provider {
 4963            Some(provider) => {
 4964                let completions = provider.completions(
 4965                    position.excerpt_id,
 4966                    &buffer,
 4967                    buffer_position,
 4968                    completion_context,
 4969                    window,
 4970                    cx,
 4971                );
 4972
 4973                let words = match completion_settings.words {
 4974                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 4975                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 4976                        .background_spawn(async move {
 4977                            buffer_snapshot.words_in_range(WordsQuery {
 4978                                fuzzy_contents: None,
 4979                                range: word_search_range,
 4980                                skip_digits,
 4981                            })
 4982                        }),
 4983                };
 4984
 4985                (words, completions)
 4986            }
 4987            None => (
 4988                cx.background_spawn(async move {
 4989                    buffer_snapshot.words_in_range(WordsQuery {
 4990                        fuzzy_contents: None,
 4991                        range: word_search_range,
 4992                        skip_digits,
 4993                    })
 4994                }),
 4995                Task::ready(Ok(None)),
 4996            ),
 4997        };
 4998
 4999        let sort_completions = provider
 5000            .as_ref()
 5001            .map_or(false, |provider| provider.sort_completions());
 5002
 5003        let filter_completions = provider
 5004            .as_ref()
 5005            .map_or(true, |provider| provider.filter_completions());
 5006
 5007        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5008
 5009        let id = post_inc(&mut self.next_completion_id);
 5010        let task = cx.spawn_in(window, async move |editor, cx| {
 5011            async move {
 5012                editor.update(cx, |this, _| {
 5013                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5014                })?;
 5015
 5016                let mut completions = Vec::new();
 5017                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5018                    completions.extend(provided_completions);
 5019                    if completion_settings.words == WordsCompletionMode::Fallback {
 5020                        words = Task::ready(BTreeMap::default());
 5021                    }
 5022                }
 5023
 5024                let mut words = words.await;
 5025                if let Some(word_to_exclude) = &word_to_exclude {
 5026                    words.remove(word_to_exclude);
 5027                }
 5028                for lsp_completion in &completions {
 5029                    words.remove(&lsp_completion.new_text);
 5030                }
 5031                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5032                    replace_range: old_range.clone(),
 5033                    new_text: word.clone(),
 5034                    label: CodeLabel::plain(word, None),
 5035                    icon_path: None,
 5036                    documentation: None,
 5037                    source: CompletionSource::BufferWord {
 5038                        word_range,
 5039                        resolved: false,
 5040                    },
 5041                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5042                    confirm: None,
 5043                }));
 5044
 5045                let menu = if completions.is_empty() {
 5046                    None
 5047                } else {
 5048                    let mut menu = CompletionsMenu::new(
 5049                        id,
 5050                        sort_completions,
 5051                        show_completion_documentation,
 5052                        ignore_completion_provider,
 5053                        position,
 5054                        buffer.clone(),
 5055                        completions.into(),
 5056                        snippet_sort_order,
 5057                    );
 5058
 5059                    menu.filter(
 5060                        if filter_completions {
 5061                            query.as_deref()
 5062                        } else {
 5063                            None
 5064                        },
 5065                        cx.background_executor().clone(),
 5066                    )
 5067                    .await;
 5068
 5069                    menu.visible().then_some(menu)
 5070                };
 5071
 5072                editor.update_in(cx, |editor, window, cx| {
 5073                    match editor.context_menu.borrow().as_ref() {
 5074                        None => {}
 5075                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5076                            if prev_menu.id > id {
 5077                                return;
 5078                            }
 5079                        }
 5080                        _ => return,
 5081                    }
 5082
 5083                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5084                        let mut menu = menu.unwrap();
 5085                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5086                        crate::hover_popover::hide_hover(editor, cx);
 5087                        *editor.context_menu.borrow_mut() =
 5088                            Some(CodeContextMenu::Completions(menu));
 5089
 5090                        if editor.show_edit_predictions_in_menu() {
 5091                            editor.update_visible_inline_completion(window, cx);
 5092                        } else {
 5093                            editor.discard_inline_completion(false, cx);
 5094                        }
 5095
 5096                        cx.notify();
 5097                    } else if editor.completion_tasks.len() <= 1 {
 5098                        // If there are no more completion tasks and the last menu was
 5099                        // empty, we should hide it.
 5100                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5101                        // If it was already hidden and we don't show inline
 5102                        // completions in the menu, we should also show the
 5103                        // inline-completion when available.
 5104                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5105                            editor.update_visible_inline_completion(window, cx);
 5106                        }
 5107                    }
 5108                })?;
 5109
 5110                anyhow::Ok(())
 5111            }
 5112            .log_err()
 5113            .await
 5114        });
 5115
 5116        self.completion_tasks.push((id, task));
 5117    }
 5118
 5119    #[cfg(feature = "test-support")]
 5120    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5121        let menu = self.context_menu.borrow();
 5122        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5123            let completions = menu.completions.borrow();
 5124            Some(completions.to_vec())
 5125        } else {
 5126            None
 5127        }
 5128    }
 5129
 5130    pub fn confirm_completion(
 5131        &mut self,
 5132        action: &ConfirmCompletion,
 5133        window: &mut Window,
 5134        cx: &mut Context<Self>,
 5135    ) -> Option<Task<Result<()>>> {
 5136        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5137        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5138    }
 5139
 5140    pub fn confirm_completion_insert(
 5141        &mut self,
 5142        _: &ConfirmCompletionInsert,
 5143        window: &mut Window,
 5144        cx: &mut Context<Self>,
 5145    ) -> Option<Task<Result<()>>> {
 5146        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5147        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5148    }
 5149
 5150    pub fn confirm_completion_replace(
 5151        &mut self,
 5152        _: &ConfirmCompletionReplace,
 5153        window: &mut Window,
 5154        cx: &mut Context<Self>,
 5155    ) -> Option<Task<Result<()>>> {
 5156        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5157        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5158    }
 5159
 5160    pub fn compose_completion(
 5161        &mut self,
 5162        action: &ComposeCompletion,
 5163        window: &mut Window,
 5164        cx: &mut Context<Self>,
 5165    ) -> Option<Task<Result<()>>> {
 5166        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5167        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5168    }
 5169
 5170    fn do_completion(
 5171        &mut self,
 5172        item_ix: Option<usize>,
 5173        intent: CompletionIntent,
 5174        window: &mut Window,
 5175        cx: &mut Context<Editor>,
 5176    ) -> Option<Task<Result<()>>> {
 5177        use language::ToOffset as _;
 5178
 5179        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5180        else {
 5181            return None;
 5182        };
 5183
 5184        let candidate_id = {
 5185            let entries = completions_menu.entries.borrow();
 5186            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5187            if self.show_edit_predictions_in_menu() {
 5188                self.discard_inline_completion(true, cx);
 5189            }
 5190            mat.candidate_id
 5191        };
 5192
 5193        let buffer_handle = completions_menu.buffer;
 5194        let completion = completions_menu
 5195            .completions
 5196            .borrow()
 5197            .get(candidate_id)?
 5198            .clone();
 5199        cx.stop_propagation();
 5200
 5201        let snapshot = self.buffer.read(cx).snapshot(cx);
 5202        let newest_anchor = self.selections.newest_anchor();
 5203
 5204        let snippet;
 5205        let new_text;
 5206        if completion.is_snippet() {
 5207            let mut snippet_source = completion.new_text.clone();
 5208            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5209                if scope.prefers_label_for_snippet_in_completion() {
 5210                    if let Some(label) = completion.label() {
 5211                        if matches!(
 5212                            completion.kind(),
 5213                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5214                        ) {
 5215                            snippet_source = label;
 5216                        }
 5217                    }
 5218                }
 5219            }
 5220            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5221            new_text = snippet.as_ref().unwrap().text.clone();
 5222        } else {
 5223            snippet = None;
 5224            new_text = completion.new_text.clone();
 5225        };
 5226
 5227        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5228        let buffer = buffer_handle.read(cx);
 5229        let replace_range_multibuffer = {
 5230            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5231            let multibuffer_anchor = snapshot
 5232                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5233                .unwrap()
 5234                ..snapshot
 5235                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5236                    .unwrap();
 5237            multibuffer_anchor.start.to_offset(&snapshot)
 5238                ..multibuffer_anchor.end.to_offset(&snapshot)
 5239        };
 5240        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5241            return None;
 5242        }
 5243
 5244        let old_text = buffer
 5245            .text_for_range(replace_range.clone())
 5246            .collect::<String>();
 5247        let lookbehind = newest_anchor
 5248            .start
 5249            .text_anchor
 5250            .to_offset(buffer)
 5251            .saturating_sub(replace_range.start);
 5252        let lookahead = replace_range
 5253            .end
 5254            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5255        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5256        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5257
 5258        let selections = self.selections.all::<usize>(cx);
 5259        let mut ranges = Vec::new();
 5260        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5261
 5262        for selection in &selections {
 5263            let range = if selection.id == newest_anchor.id {
 5264                replace_range_multibuffer.clone()
 5265            } else {
 5266                let mut range = selection.range();
 5267
 5268                // if prefix is present, don't duplicate it
 5269                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5270                    range.start = range.start.saturating_sub(lookbehind);
 5271
 5272                    // if suffix is also present, mimic the newest cursor and replace it
 5273                    if selection.id != newest_anchor.id
 5274                        && snapshot.contains_str_at(range.end, suffix)
 5275                    {
 5276                        range.end += lookahead;
 5277                    }
 5278                }
 5279                range
 5280            };
 5281
 5282            ranges.push(range.clone());
 5283
 5284            if !self.linked_edit_ranges.is_empty() {
 5285                let start_anchor = snapshot.anchor_before(range.start);
 5286                let end_anchor = snapshot.anchor_after(range.end);
 5287                if let Some(ranges) = self
 5288                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5289                {
 5290                    for (buffer, edits) in ranges {
 5291                        linked_edits
 5292                            .entry(buffer.clone())
 5293                            .or_default()
 5294                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5295                    }
 5296                }
 5297            }
 5298        }
 5299
 5300        cx.emit(EditorEvent::InputHandled {
 5301            utf16_range_to_replace: None,
 5302            text: new_text.clone().into(),
 5303        });
 5304
 5305        self.transact(window, cx, |this, window, cx| {
 5306            if let Some(mut snippet) = snippet {
 5307                snippet.text = new_text.to_string();
 5308                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5309            } else {
 5310                this.buffer.update(cx, |buffer, cx| {
 5311                    let auto_indent = match completion.insert_text_mode {
 5312                        Some(InsertTextMode::AS_IS) => None,
 5313                        _ => this.autoindent_mode.clone(),
 5314                    };
 5315                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5316                    buffer.edit(edits, auto_indent, cx);
 5317                });
 5318            }
 5319            for (buffer, edits) in linked_edits {
 5320                buffer.update(cx, |buffer, cx| {
 5321                    let snapshot = buffer.snapshot();
 5322                    let edits = edits
 5323                        .into_iter()
 5324                        .map(|(range, text)| {
 5325                            use text::ToPoint as TP;
 5326                            let end_point = TP::to_point(&range.end, &snapshot);
 5327                            let start_point = TP::to_point(&range.start, &snapshot);
 5328                            (start_point..end_point, text)
 5329                        })
 5330                        .sorted_by_key(|(range, _)| range.start);
 5331                    buffer.edit(edits, None, cx);
 5332                })
 5333            }
 5334
 5335            this.refresh_inline_completion(true, false, window, cx);
 5336        });
 5337
 5338        let show_new_completions_on_confirm = completion
 5339            .confirm
 5340            .as_ref()
 5341            .map_or(false, |confirm| confirm(intent, window, cx));
 5342        if show_new_completions_on_confirm {
 5343            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5344        }
 5345
 5346        let provider = self.completion_provider.as_ref()?;
 5347        drop(completion);
 5348        let apply_edits = provider.apply_additional_edits_for_completion(
 5349            buffer_handle,
 5350            completions_menu.completions.clone(),
 5351            candidate_id,
 5352            true,
 5353            cx,
 5354        );
 5355
 5356        let editor_settings = EditorSettings::get_global(cx);
 5357        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5358            // After the code completion is finished, users often want to know what signatures are needed.
 5359            // so we should automatically call signature_help
 5360            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5361        }
 5362
 5363        Some(cx.foreground_executor().spawn(async move {
 5364            apply_edits.await?;
 5365            Ok(())
 5366        }))
 5367    }
 5368
 5369    pub fn toggle_code_actions(
 5370        &mut self,
 5371        action: &ToggleCodeActions,
 5372        window: &mut Window,
 5373        cx: &mut Context<Self>,
 5374    ) {
 5375        let quick_launch = action.quick_launch;
 5376        let mut context_menu = self.context_menu.borrow_mut();
 5377        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5378            if code_actions.deployed_from_indicator == action.deployed_from_indicator {
 5379                // Toggle if we're selecting the same one
 5380                *context_menu = None;
 5381                cx.notify();
 5382                return;
 5383            } else {
 5384                // Otherwise, clear it and start a new one
 5385                *context_menu = None;
 5386                cx.notify();
 5387            }
 5388        }
 5389        drop(context_menu);
 5390        let snapshot = self.snapshot(window, cx);
 5391        let deployed_from_indicator = action.deployed_from_indicator;
 5392        let mut task = self.code_actions_task.take();
 5393        let action = action.clone();
 5394        cx.spawn_in(window, async move |editor, cx| {
 5395            while let Some(prev_task) = task {
 5396                prev_task.await.log_err();
 5397                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5398            }
 5399
 5400            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5401                if editor.focus_handle.is_focused(window) {
 5402                    let multibuffer_point = action
 5403                        .deployed_from_indicator
 5404                        .map(|row| DisplayPoint::new(row, 0).to_point(&snapshot))
 5405                        .unwrap_or_else(|| editor.selections.newest::<Point>(cx).head());
 5406                    let (buffer, buffer_row) = snapshot
 5407                        .buffer_snapshot
 5408                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5409                        .and_then(|(buffer_snapshot, range)| {
 5410                            editor
 5411                                .buffer
 5412                                .read(cx)
 5413                                .buffer(buffer_snapshot.remote_id())
 5414                                .map(|buffer| (buffer, range.start.row))
 5415                        })?;
 5416                    let (_, code_actions) = editor
 5417                        .available_code_actions
 5418                        .clone()
 5419                        .and_then(|(location, code_actions)| {
 5420                            let snapshot = location.buffer.read(cx).snapshot();
 5421                            let point_range = location.range.to_point(&snapshot);
 5422                            let point_range = point_range.start.row..=point_range.end.row;
 5423                            if point_range.contains(&buffer_row) {
 5424                                Some((location, code_actions))
 5425                            } else {
 5426                                None
 5427                            }
 5428                        })
 5429                        .unzip();
 5430                    let buffer_id = buffer.read(cx).remote_id();
 5431                    let tasks = editor
 5432                        .tasks
 5433                        .get(&(buffer_id, buffer_row))
 5434                        .map(|t| Arc::new(t.to_owned()));
 5435                    if tasks.is_none() && code_actions.is_none() {
 5436                        return None;
 5437                    }
 5438
 5439                    editor.completion_tasks.clear();
 5440                    editor.discard_inline_completion(false, cx);
 5441                    let task_context =
 5442                        tasks
 5443                            .as_ref()
 5444                            .zip(editor.project.clone())
 5445                            .map(|(tasks, project)| {
 5446                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5447                            });
 5448
 5449                    Some(cx.spawn_in(window, async move |editor, cx| {
 5450                        let task_context = match task_context {
 5451                            Some(task_context) => task_context.await,
 5452                            None => None,
 5453                        };
 5454                        let resolved_tasks =
 5455                            tasks
 5456                                .zip(task_context.clone())
 5457                                .map(|(tasks, task_context)| ResolvedTasks {
 5458                                    templates: tasks.resolve(&task_context).collect(),
 5459                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5460                                        multibuffer_point.row,
 5461                                        tasks.column,
 5462                                    )),
 5463                                });
 5464                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5465                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5466                                maybe!({
 5467                                    let project = editor.project.as_ref()?;
 5468                                    let dap_store = project.read(cx).dap_store();
 5469                                    let mut scenarios = vec![];
 5470                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5471                                    let buffer = buffer.read(cx);
 5472                                    let language = buffer.language()?;
 5473                                    let file = buffer.file();
 5474                                    let debug_adapter =
 5475                                        language_settings(language.name().into(), file, cx)
 5476                                            .debuggers
 5477                                            .first()
 5478                                            .map(SharedString::from)
 5479                                            .or_else(|| {
 5480                                                language
 5481                                                    .config()
 5482                                                    .debuggers
 5483                                                    .first()
 5484                                                    .map(SharedString::from)
 5485                                            })?;
 5486
 5487                                    dap_store.update(cx, |dap_store, cx| {
 5488                                        for (_, task) in &resolved_tasks.templates {
 5489                                            if let Some(scenario) = dap_store
 5490                                                .debug_scenario_for_build_task(
 5491                                                    task.original_task().clone(),
 5492                                                    debug_adapter.clone().into(),
 5493                                                    task.display_label().to_owned().into(),
 5494                                                    cx,
 5495                                                )
 5496                                            {
 5497                                                scenarios.push(scenario);
 5498                                            }
 5499                                        }
 5500                                    });
 5501                                    Some(scenarios)
 5502                                })
 5503                                .unwrap_or_default()
 5504                            } else {
 5505                                vec![]
 5506                            }
 5507                        })?;
 5508                        let spawn_straight_away = quick_launch
 5509                            && resolved_tasks
 5510                                .as_ref()
 5511                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5512                            && code_actions
 5513                                .as_ref()
 5514                                .map_or(true, |actions| actions.is_empty())
 5515                            && debug_scenarios.is_empty();
 5516                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5517                            crate::hover_popover::hide_hover(editor, cx);
 5518                            *editor.context_menu.borrow_mut() =
 5519                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5520                                    buffer,
 5521                                    actions: CodeActionContents::new(
 5522                                        resolved_tasks,
 5523                                        code_actions,
 5524                                        debug_scenarios,
 5525                                        task_context.unwrap_or_default(),
 5526                                    ),
 5527                                    selected_item: Default::default(),
 5528                                    scroll_handle: UniformListScrollHandle::default(),
 5529                                    deployed_from_indicator,
 5530                                }));
 5531                            if spawn_straight_away {
 5532                                if let Some(task) = editor.confirm_code_action(
 5533                                    &ConfirmCodeAction { item_ix: Some(0) },
 5534                                    window,
 5535                                    cx,
 5536                                ) {
 5537                                    cx.notify();
 5538                                    return task;
 5539                                }
 5540                            }
 5541                            cx.notify();
 5542                            Task::ready(Ok(()))
 5543                        }) {
 5544                            task.await
 5545                        } else {
 5546                            Ok(())
 5547                        }
 5548                    }))
 5549                } else {
 5550                    Some(Task::ready(Ok(())))
 5551                }
 5552            })?;
 5553            if let Some(task) = spawned_test_task {
 5554                task.await?;
 5555            }
 5556
 5557            anyhow::Ok(())
 5558        })
 5559        .detach_and_log_err(cx);
 5560    }
 5561
 5562    pub fn confirm_code_action(
 5563        &mut self,
 5564        action: &ConfirmCodeAction,
 5565        window: &mut Window,
 5566        cx: &mut Context<Self>,
 5567    ) -> Option<Task<Result<()>>> {
 5568        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5569
 5570        let actions_menu =
 5571            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5572                menu
 5573            } else {
 5574                return None;
 5575            };
 5576
 5577        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5578        let action = actions_menu.actions.get(action_ix)?;
 5579        let title = action.label();
 5580        let buffer = actions_menu.buffer;
 5581        let workspace = self.workspace()?;
 5582
 5583        match action {
 5584            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5585                workspace.update(cx, |workspace, cx| {
 5586                    workspace.schedule_resolved_task(
 5587                        task_source_kind,
 5588                        resolved_task,
 5589                        false,
 5590                        window,
 5591                        cx,
 5592                    );
 5593
 5594                    Some(Task::ready(Ok(())))
 5595                })
 5596            }
 5597            CodeActionsItem::CodeAction {
 5598                excerpt_id,
 5599                action,
 5600                provider,
 5601            } => {
 5602                let apply_code_action =
 5603                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5604                let workspace = workspace.downgrade();
 5605                Some(cx.spawn_in(window, async move |editor, cx| {
 5606                    let project_transaction = apply_code_action.await?;
 5607                    Self::open_project_transaction(
 5608                        &editor,
 5609                        workspace,
 5610                        project_transaction,
 5611                        title,
 5612                        cx,
 5613                    )
 5614                    .await
 5615                }))
 5616            }
 5617            CodeActionsItem::DebugScenario(scenario) => {
 5618                let context = actions_menu.actions.context.clone();
 5619
 5620                workspace.update(cx, |workspace, cx| {
 5621                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5622                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5623                });
 5624                Some(Task::ready(Ok(())))
 5625            }
 5626        }
 5627    }
 5628
 5629    pub async fn open_project_transaction(
 5630        this: &WeakEntity<Editor>,
 5631        workspace: WeakEntity<Workspace>,
 5632        transaction: ProjectTransaction,
 5633        title: String,
 5634        cx: &mut AsyncWindowContext,
 5635    ) -> Result<()> {
 5636        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5637        cx.update(|_, cx| {
 5638            entries.sort_unstable_by_key(|(buffer, _)| {
 5639                buffer.read(cx).file().map(|f| f.path().clone())
 5640            });
 5641        })?;
 5642
 5643        // If the project transaction's edits are all contained within this editor, then
 5644        // avoid opening a new editor to display them.
 5645
 5646        if let Some((buffer, transaction)) = entries.first() {
 5647            if entries.len() == 1 {
 5648                let excerpt = this.update(cx, |editor, cx| {
 5649                    editor
 5650                        .buffer()
 5651                        .read(cx)
 5652                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5653                })?;
 5654                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5655                    if excerpted_buffer == *buffer {
 5656                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5657                            let excerpt_range = excerpt_range.to_offset(buffer);
 5658                            buffer
 5659                                .edited_ranges_for_transaction::<usize>(transaction)
 5660                                .all(|range| {
 5661                                    excerpt_range.start <= range.start
 5662                                        && excerpt_range.end >= range.end
 5663                                })
 5664                        })?;
 5665
 5666                        if all_edits_within_excerpt {
 5667                            return Ok(());
 5668                        }
 5669                    }
 5670                }
 5671            }
 5672        } else {
 5673            return Ok(());
 5674        }
 5675
 5676        let mut ranges_to_highlight = Vec::new();
 5677        let excerpt_buffer = cx.new(|cx| {
 5678            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5679            for (buffer_handle, transaction) in &entries {
 5680                let edited_ranges = buffer_handle
 5681                    .read(cx)
 5682                    .edited_ranges_for_transaction::<Point>(transaction)
 5683                    .collect::<Vec<_>>();
 5684                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5685                    PathKey::for_buffer(buffer_handle, cx),
 5686                    buffer_handle.clone(),
 5687                    edited_ranges,
 5688                    DEFAULT_MULTIBUFFER_CONTEXT,
 5689                    cx,
 5690                );
 5691
 5692                ranges_to_highlight.extend(ranges);
 5693            }
 5694            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5695            multibuffer
 5696        })?;
 5697
 5698        workspace.update_in(cx, |workspace, window, cx| {
 5699            let project = workspace.project().clone();
 5700            let editor =
 5701                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5702            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5703            editor.update(cx, |editor, cx| {
 5704                editor.highlight_background::<Self>(
 5705                    &ranges_to_highlight,
 5706                    |theme| theme.editor_highlighted_line_background,
 5707                    cx,
 5708                );
 5709            });
 5710        })?;
 5711
 5712        Ok(())
 5713    }
 5714
 5715    pub fn clear_code_action_providers(&mut self) {
 5716        self.code_action_providers.clear();
 5717        self.available_code_actions.take();
 5718    }
 5719
 5720    pub fn add_code_action_provider(
 5721        &mut self,
 5722        provider: Rc<dyn CodeActionProvider>,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) {
 5726        if self
 5727            .code_action_providers
 5728            .iter()
 5729            .any(|existing_provider| existing_provider.id() == provider.id())
 5730        {
 5731            return;
 5732        }
 5733
 5734        self.code_action_providers.push(provider);
 5735        self.refresh_code_actions(window, cx);
 5736    }
 5737
 5738    pub fn remove_code_action_provider(
 5739        &mut self,
 5740        id: Arc<str>,
 5741        window: &mut Window,
 5742        cx: &mut Context<Self>,
 5743    ) {
 5744        self.code_action_providers
 5745            .retain(|provider| provider.id() != id);
 5746        self.refresh_code_actions(window, cx);
 5747    }
 5748
 5749    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5750        let newest_selection = self.selections.newest_anchor().clone();
 5751        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5752        let buffer = self.buffer.read(cx);
 5753        if newest_selection.head().diff_base_anchor.is_some() {
 5754            return None;
 5755        }
 5756        let (start_buffer, start) =
 5757            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5758        let (end_buffer, end) =
 5759            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5760        if start_buffer != end_buffer {
 5761            return None;
 5762        }
 5763
 5764        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5765            cx.background_executor()
 5766                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5767                .await;
 5768
 5769            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5770                let providers = this.code_action_providers.clone();
 5771                let tasks = this
 5772                    .code_action_providers
 5773                    .iter()
 5774                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5775                    .collect::<Vec<_>>();
 5776                (providers, tasks)
 5777            })?;
 5778
 5779            let mut actions = Vec::new();
 5780            for (provider, provider_actions) in
 5781                providers.into_iter().zip(future::join_all(tasks).await)
 5782            {
 5783                if let Some(provider_actions) = provider_actions.log_err() {
 5784                    actions.extend(provider_actions.into_iter().map(|action| {
 5785                        AvailableCodeAction {
 5786                            excerpt_id: newest_selection.start.excerpt_id,
 5787                            action,
 5788                            provider: provider.clone(),
 5789                        }
 5790                    }));
 5791                }
 5792            }
 5793
 5794            this.update(cx, |this, cx| {
 5795                this.available_code_actions = if actions.is_empty() {
 5796                    None
 5797                } else {
 5798                    Some((
 5799                        Location {
 5800                            buffer: start_buffer,
 5801                            range: start..end,
 5802                        },
 5803                        actions.into(),
 5804                    ))
 5805                };
 5806                cx.notify();
 5807            })
 5808        }));
 5809        None
 5810    }
 5811
 5812    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5813        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5814            self.show_git_blame_inline = false;
 5815
 5816            self.show_git_blame_inline_delay_task =
 5817                Some(cx.spawn_in(window, async move |this, cx| {
 5818                    cx.background_executor().timer(delay).await;
 5819
 5820                    this.update(cx, |this, cx| {
 5821                        this.show_git_blame_inline = true;
 5822                        cx.notify();
 5823                    })
 5824                    .log_err();
 5825                }));
 5826        }
 5827    }
 5828
 5829    fn show_blame_popover(
 5830        &mut self,
 5831        blame_entry: &BlameEntry,
 5832        position: gpui::Point<Pixels>,
 5833        cx: &mut Context<Self>,
 5834    ) {
 5835        if let Some(state) = &mut self.inline_blame_popover {
 5836            state.hide_task.take();
 5837            cx.notify();
 5838        } else {
 5839            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5840            let show_task = cx.spawn(async move |editor, cx| {
 5841                cx.background_executor()
 5842                    .timer(std::time::Duration::from_millis(delay))
 5843                    .await;
 5844                editor
 5845                    .update(cx, |editor, cx| {
 5846                        if let Some(state) = &mut editor.inline_blame_popover {
 5847                            state.show_task = None;
 5848                            cx.notify();
 5849                        }
 5850                    })
 5851                    .ok();
 5852            });
 5853            let Some(blame) = self.blame.as_ref() else {
 5854                return;
 5855            };
 5856            let blame = blame.read(cx);
 5857            let details = blame.details_for_entry(&blame_entry);
 5858            let markdown = cx.new(|cx| {
 5859                Markdown::new(
 5860                    details
 5861                        .as_ref()
 5862                        .map(|message| message.message.clone())
 5863                        .unwrap_or_default(),
 5864                    None,
 5865                    None,
 5866                    cx,
 5867                )
 5868            });
 5869            self.inline_blame_popover = Some(InlineBlamePopover {
 5870                position,
 5871                show_task: Some(show_task),
 5872                hide_task: None,
 5873                popover_bounds: None,
 5874                popover_state: InlineBlamePopoverState {
 5875                    scroll_handle: ScrollHandle::new(),
 5876                    commit_message: details,
 5877                    markdown,
 5878                },
 5879            });
 5880        }
 5881    }
 5882
 5883    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 5884        if let Some(state) = &mut self.inline_blame_popover {
 5885            if state.show_task.is_some() {
 5886                self.inline_blame_popover.take();
 5887                cx.notify();
 5888            } else {
 5889                let hide_task = cx.spawn(async move |editor, cx| {
 5890                    cx.background_executor()
 5891                        .timer(std::time::Duration::from_millis(100))
 5892                        .await;
 5893                    editor
 5894                        .update(cx, |editor, cx| {
 5895                            editor.inline_blame_popover.take();
 5896                            cx.notify();
 5897                        })
 5898                        .ok();
 5899                });
 5900                state.hide_task = Some(hide_task);
 5901            }
 5902        }
 5903    }
 5904
 5905    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 5906        if self.pending_rename.is_some() {
 5907            return None;
 5908        }
 5909
 5910        let provider = self.semantics_provider.clone()?;
 5911        let buffer = self.buffer.read(cx);
 5912        let newest_selection = self.selections.newest_anchor().clone();
 5913        let cursor_position = newest_selection.head();
 5914        let (cursor_buffer, cursor_buffer_position) =
 5915            buffer.text_anchor_for_position(cursor_position, cx)?;
 5916        let (tail_buffer, tail_buffer_position) =
 5917            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 5918        if cursor_buffer != tail_buffer {
 5919            return None;
 5920        }
 5921
 5922        let snapshot = cursor_buffer.read(cx).snapshot();
 5923        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 5924        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 5925        if start_word_range != end_word_range {
 5926            self.document_highlights_task.take();
 5927            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 5928            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 5929            return None;
 5930        }
 5931
 5932        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 5933        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 5934            cx.background_executor()
 5935                .timer(Duration::from_millis(debounce))
 5936                .await;
 5937
 5938            let highlights = if let Some(highlights) = cx
 5939                .update(|cx| {
 5940                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 5941                })
 5942                .ok()
 5943                .flatten()
 5944            {
 5945                highlights.await.log_err()
 5946            } else {
 5947                None
 5948            };
 5949
 5950            if let Some(highlights) = highlights {
 5951                this.update(cx, |this, cx| {
 5952                    if this.pending_rename.is_some() {
 5953                        return;
 5954                    }
 5955
 5956                    let buffer_id = cursor_position.buffer_id;
 5957                    let buffer = this.buffer.read(cx);
 5958                    if !buffer
 5959                        .text_anchor_for_position(cursor_position, cx)
 5960                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 5961                    {
 5962                        return;
 5963                    }
 5964
 5965                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 5966                    let mut write_ranges = Vec::new();
 5967                    let mut read_ranges = Vec::new();
 5968                    for highlight in highlights {
 5969                        for (excerpt_id, excerpt_range) in
 5970                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 5971                        {
 5972                            let start = highlight
 5973                                .range
 5974                                .start
 5975                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 5976                            let end = highlight
 5977                                .range
 5978                                .end
 5979                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 5980                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 5981                                continue;
 5982                            }
 5983
 5984                            let range = Anchor {
 5985                                buffer_id,
 5986                                excerpt_id,
 5987                                text_anchor: start,
 5988                                diff_base_anchor: None,
 5989                            }..Anchor {
 5990                                buffer_id,
 5991                                excerpt_id,
 5992                                text_anchor: end,
 5993                                diff_base_anchor: None,
 5994                            };
 5995                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 5996                                write_ranges.push(range);
 5997                            } else {
 5998                                read_ranges.push(range);
 5999                            }
 6000                        }
 6001                    }
 6002
 6003                    this.highlight_background::<DocumentHighlightRead>(
 6004                        &read_ranges,
 6005                        |theme| theme.editor_document_highlight_read_background,
 6006                        cx,
 6007                    );
 6008                    this.highlight_background::<DocumentHighlightWrite>(
 6009                        &write_ranges,
 6010                        |theme| theme.editor_document_highlight_write_background,
 6011                        cx,
 6012                    );
 6013                    cx.notify();
 6014                })
 6015                .log_err();
 6016            }
 6017        }));
 6018        None
 6019    }
 6020
 6021    fn prepare_highlight_query_from_selection(
 6022        &mut self,
 6023        cx: &mut Context<Editor>,
 6024    ) -> Option<(String, Range<Anchor>)> {
 6025        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6026            return None;
 6027        }
 6028        if !EditorSettings::get_global(cx).selection_highlight {
 6029            return None;
 6030        }
 6031        if self.selections.count() != 1 || self.selections.line_mode {
 6032            return None;
 6033        }
 6034        let selection = self.selections.newest::<Point>(cx);
 6035        if selection.is_empty() || selection.start.row != selection.end.row {
 6036            return None;
 6037        }
 6038        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6039        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6040        let query = multi_buffer_snapshot
 6041            .text_for_range(selection_anchor_range.clone())
 6042            .collect::<String>();
 6043        if query.trim().is_empty() {
 6044            return None;
 6045        }
 6046        Some((query, selection_anchor_range))
 6047    }
 6048
 6049    fn update_selection_occurrence_highlights(
 6050        &mut self,
 6051        query_text: String,
 6052        query_range: Range<Anchor>,
 6053        multi_buffer_range_to_query: Range<Point>,
 6054        use_debounce: bool,
 6055        window: &mut Window,
 6056        cx: &mut Context<Editor>,
 6057    ) -> Task<()> {
 6058        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            if use_debounce {
 6061                cx.background_executor()
 6062                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6063                    .await;
 6064            }
 6065            let match_task = cx.background_spawn(async move {
 6066                let buffer_ranges = multi_buffer_snapshot
 6067                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6068                    .into_iter()
 6069                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6070                let mut match_ranges = Vec::new();
 6071                let Ok(regex) = project::search::SearchQuery::text(
 6072                    query_text.clone(),
 6073                    false,
 6074                    false,
 6075                    false,
 6076                    Default::default(),
 6077                    Default::default(),
 6078                    false,
 6079                    None,
 6080                ) else {
 6081                    return Vec::default();
 6082                };
 6083                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6084                    match_ranges.extend(
 6085                        regex
 6086                            .search(&buffer_snapshot, Some(search_range.clone()))
 6087                            .await
 6088                            .into_iter()
 6089                            .filter_map(|match_range| {
 6090                                let match_start = buffer_snapshot
 6091                                    .anchor_after(search_range.start + match_range.start);
 6092                                let match_end = buffer_snapshot
 6093                                    .anchor_before(search_range.start + match_range.end);
 6094                                let match_anchor_range = Anchor::range_in_buffer(
 6095                                    excerpt_id,
 6096                                    buffer_snapshot.remote_id(),
 6097                                    match_start..match_end,
 6098                                );
 6099                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6100                            }),
 6101                    );
 6102                }
 6103                match_ranges
 6104            });
 6105            let match_ranges = match_task.await;
 6106            editor
 6107                .update_in(cx, |editor, _, cx| {
 6108                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6109                    if !match_ranges.is_empty() {
 6110                        editor.highlight_background::<SelectedTextHighlight>(
 6111                            &match_ranges,
 6112                            |theme| theme.editor_document_highlight_bracket_background,
 6113                            cx,
 6114                        )
 6115                    }
 6116                })
 6117                .log_err();
 6118        })
 6119    }
 6120
 6121    fn refresh_selected_text_highlights(
 6122        &mut self,
 6123        on_buffer_edit: bool,
 6124        window: &mut Window,
 6125        cx: &mut Context<Editor>,
 6126    ) {
 6127        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6128        else {
 6129            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6130            self.quick_selection_highlight_task.take();
 6131            self.debounced_selection_highlight_task.take();
 6132            return;
 6133        };
 6134        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6135        if on_buffer_edit
 6136            || self
 6137                .quick_selection_highlight_task
 6138                .as_ref()
 6139                .map_or(true, |(prev_anchor_range, _)| {
 6140                    prev_anchor_range != &query_range
 6141                })
 6142        {
 6143            let multi_buffer_visible_start = self
 6144                .scroll_manager
 6145                .anchor()
 6146                .anchor
 6147                .to_point(&multi_buffer_snapshot);
 6148            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6149                multi_buffer_visible_start
 6150                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6151                Bias::Left,
 6152            );
 6153            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6154            self.quick_selection_highlight_task = Some((
 6155                query_range.clone(),
 6156                self.update_selection_occurrence_highlights(
 6157                    query_text.clone(),
 6158                    query_range.clone(),
 6159                    multi_buffer_visible_range,
 6160                    false,
 6161                    window,
 6162                    cx,
 6163                ),
 6164            ));
 6165        }
 6166        if on_buffer_edit
 6167            || self
 6168                .debounced_selection_highlight_task
 6169                .as_ref()
 6170                .map_or(true, |(prev_anchor_range, _)| {
 6171                    prev_anchor_range != &query_range
 6172                })
 6173        {
 6174            let multi_buffer_start = multi_buffer_snapshot
 6175                .anchor_before(0)
 6176                .to_point(&multi_buffer_snapshot);
 6177            let multi_buffer_end = multi_buffer_snapshot
 6178                .anchor_after(multi_buffer_snapshot.len())
 6179                .to_point(&multi_buffer_snapshot);
 6180            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6181            self.debounced_selection_highlight_task = Some((
 6182                query_range.clone(),
 6183                self.update_selection_occurrence_highlights(
 6184                    query_text,
 6185                    query_range,
 6186                    multi_buffer_full_range,
 6187                    true,
 6188                    window,
 6189                    cx,
 6190                ),
 6191            ));
 6192        }
 6193    }
 6194
 6195    pub fn refresh_inline_completion(
 6196        &mut self,
 6197        debounce: bool,
 6198        user_requested: bool,
 6199        window: &mut Window,
 6200        cx: &mut Context<Self>,
 6201    ) -> Option<()> {
 6202        let provider = self.edit_prediction_provider()?;
 6203        let cursor = self.selections.newest_anchor().head();
 6204        let (buffer, cursor_buffer_position) =
 6205            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6206
 6207        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6208            self.discard_inline_completion(false, cx);
 6209            return None;
 6210        }
 6211
 6212        if !user_requested
 6213            && (!self.should_show_edit_predictions()
 6214                || !self.is_focused(window)
 6215                || buffer.read(cx).is_empty())
 6216        {
 6217            self.discard_inline_completion(false, cx);
 6218            return None;
 6219        }
 6220
 6221        self.update_visible_inline_completion(window, cx);
 6222        provider.refresh(
 6223            self.project.clone(),
 6224            buffer,
 6225            cursor_buffer_position,
 6226            debounce,
 6227            cx,
 6228        );
 6229        Some(())
 6230    }
 6231
 6232    fn show_edit_predictions_in_menu(&self) -> bool {
 6233        match self.edit_prediction_settings {
 6234            EditPredictionSettings::Disabled => false,
 6235            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6236        }
 6237    }
 6238
 6239    pub fn edit_predictions_enabled(&self) -> bool {
 6240        match self.edit_prediction_settings {
 6241            EditPredictionSettings::Disabled => false,
 6242            EditPredictionSettings::Enabled { .. } => true,
 6243        }
 6244    }
 6245
 6246    fn edit_prediction_requires_modifier(&self) -> bool {
 6247        match self.edit_prediction_settings {
 6248            EditPredictionSettings::Disabled => false,
 6249            EditPredictionSettings::Enabled {
 6250                preview_requires_modifier,
 6251                ..
 6252            } => preview_requires_modifier,
 6253        }
 6254    }
 6255
 6256    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6257        if self.edit_prediction_provider.is_none() {
 6258            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6259        } else {
 6260            let selection = self.selections.newest_anchor();
 6261            let cursor = selection.head();
 6262
 6263            if let Some((buffer, cursor_buffer_position)) =
 6264                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6265            {
 6266                self.edit_prediction_settings =
 6267                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6268            }
 6269        }
 6270    }
 6271
 6272    fn edit_prediction_settings_at_position(
 6273        &self,
 6274        buffer: &Entity<Buffer>,
 6275        buffer_position: language::Anchor,
 6276        cx: &App,
 6277    ) -> EditPredictionSettings {
 6278        if !self.mode.is_full()
 6279            || !self.show_inline_completions_override.unwrap_or(true)
 6280            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6281        {
 6282            return EditPredictionSettings::Disabled;
 6283        }
 6284
 6285        let buffer = buffer.read(cx);
 6286
 6287        let file = buffer.file();
 6288
 6289        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6290            return EditPredictionSettings::Disabled;
 6291        };
 6292
 6293        let by_provider = matches!(
 6294            self.menu_inline_completions_policy,
 6295            MenuInlineCompletionsPolicy::ByProvider
 6296        );
 6297
 6298        let show_in_menu = by_provider
 6299            && self
 6300                .edit_prediction_provider
 6301                .as_ref()
 6302                .map_or(false, |provider| {
 6303                    provider.provider.show_completions_in_menu()
 6304                });
 6305
 6306        let preview_requires_modifier =
 6307            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6308
 6309        EditPredictionSettings::Enabled {
 6310            show_in_menu,
 6311            preview_requires_modifier,
 6312        }
 6313    }
 6314
 6315    fn should_show_edit_predictions(&self) -> bool {
 6316        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6317    }
 6318
 6319    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6320        matches!(
 6321            self.edit_prediction_preview,
 6322            EditPredictionPreview::Active { .. }
 6323        )
 6324    }
 6325
 6326    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6327        let cursor = self.selections.newest_anchor().head();
 6328        if let Some((buffer, cursor_position)) =
 6329            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6330        {
 6331            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6332        } else {
 6333            false
 6334        }
 6335    }
 6336
 6337    pub fn supports_minimap(&self, cx: &App) -> bool {
 6338        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6339    }
 6340
 6341    fn edit_predictions_enabled_in_buffer(
 6342        &self,
 6343        buffer: &Entity<Buffer>,
 6344        buffer_position: language::Anchor,
 6345        cx: &App,
 6346    ) -> bool {
 6347        maybe!({
 6348            if self.read_only(cx) {
 6349                return Some(false);
 6350            }
 6351            let provider = self.edit_prediction_provider()?;
 6352            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6353                return Some(false);
 6354            }
 6355            let buffer = buffer.read(cx);
 6356            let Some(file) = buffer.file() else {
 6357                return Some(true);
 6358            };
 6359            let settings = all_language_settings(Some(file), cx);
 6360            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6361        })
 6362        .unwrap_or(false)
 6363    }
 6364
 6365    fn cycle_inline_completion(
 6366        &mut self,
 6367        direction: Direction,
 6368        window: &mut Window,
 6369        cx: &mut Context<Self>,
 6370    ) -> Option<()> {
 6371        let provider = self.edit_prediction_provider()?;
 6372        let cursor = self.selections.newest_anchor().head();
 6373        let (buffer, cursor_buffer_position) =
 6374            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6375        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6376            return None;
 6377        }
 6378
 6379        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6380        self.update_visible_inline_completion(window, cx);
 6381
 6382        Some(())
 6383    }
 6384
 6385    pub fn show_inline_completion(
 6386        &mut self,
 6387        _: &ShowEditPrediction,
 6388        window: &mut Window,
 6389        cx: &mut Context<Self>,
 6390    ) {
 6391        if !self.has_active_inline_completion() {
 6392            self.refresh_inline_completion(false, true, window, cx);
 6393            return;
 6394        }
 6395
 6396        self.update_visible_inline_completion(window, cx);
 6397    }
 6398
 6399    pub fn display_cursor_names(
 6400        &mut self,
 6401        _: &DisplayCursorNames,
 6402        window: &mut Window,
 6403        cx: &mut Context<Self>,
 6404    ) {
 6405        self.show_cursor_names(window, cx);
 6406    }
 6407
 6408    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6409        self.show_cursor_names = true;
 6410        cx.notify();
 6411        cx.spawn_in(window, async move |this, cx| {
 6412            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6413            this.update(cx, |this, cx| {
 6414                this.show_cursor_names = false;
 6415                cx.notify()
 6416            })
 6417            .ok()
 6418        })
 6419        .detach();
 6420    }
 6421
 6422    pub fn next_edit_prediction(
 6423        &mut self,
 6424        _: &NextEditPrediction,
 6425        window: &mut Window,
 6426        cx: &mut Context<Self>,
 6427    ) {
 6428        if self.has_active_inline_completion() {
 6429            self.cycle_inline_completion(Direction::Next, window, cx);
 6430        } else {
 6431            let is_copilot_disabled = self
 6432                .refresh_inline_completion(false, true, window, cx)
 6433                .is_none();
 6434            if is_copilot_disabled {
 6435                cx.propagate();
 6436            }
 6437        }
 6438    }
 6439
 6440    pub fn previous_edit_prediction(
 6441        &mut self,
 6442        _: &PreviousEditPrediction,
 6443        window: &mut Window,
 6444        cx: &mut Context<Self>,
 6445    ) {
 6446        if self.has_active_inline_completion() {
 6447            self.cycle_inline_completion(Direction::Prev, window, cx);
 6448        } else {
 6449            let is_copilot_disabled = self
 6450                .refresh_inline_completion(false, true, window, cx)
 6451                .is_none();
 6452            if is_copilot_disabled {
 6453                cx.propagate();
 6454            }
 6455        }
 6456    }
 6457
 6458    pub fn accept_edit_prediction(
 6459        &mut self,
 6460        _: &AcceptEditPrediction,
 6461        window: &mut Window,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        if self.show_edit_predictions_in_menu() {
 6465            self.hide_context_menu(window, cx);
 6466        }
 6467
 6468        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6469            return;
 6470        };
 6471
 6472        self.report_inline_completion_event(
 6473            active_inline_completion.completion_id.clone(),
 6474            true,
 6475            cx,
 6476        );
 6477
 6478        match &active_inline_completion.completion {
 6479            InlineCompletion::Move { target, .. } => {
 6480                let target = *target;
 6481
 6482                if let Some(position_map) = &self.last_position_map {
 6483                    if position_map
 6484                        .visible_row_range
 6485                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6486                        || !self.edit_prediction_requires_modifier()
 6487                    {
 6488                        self.unfold_ranges(&[target..target], true, false, cx);
 6489                        // Note that this is also done in vim's handler of the Tab action.
 6490                        self.change_selections(
 6491                            Some(Autoscroll::newest()),
 6492                            window,
 6493                            cx,
 6494                            |selections| {
 6495                                selections.select_anchor_ranges([target..target]);
 6496                            },
 6497                        );
 6498                        self.clear_row_highlights::<EditPredictionPreview>();
 6499
 6500                        self.edit_prediction_preview
 6501                            .set_previous_scroll_position(None);
 6502                    } else {
 6503                        self.edit_prediction_preview
 6504                            .set_previous_scroll_position(Some(
 6505                                position_map.snapshot.scroll_anchor,
 6506                            ));
 6507
 6508                        self.highlight_rows::<EditPredictionPreview>(
 6509                            target..target,
 6510                            cx.theme().colors().editor_highlighted_line_background,
 6511                            RowHighlightOptions {
 6512                                autoscroll: true,
 6513                                ..Default::default()
 6514                            },
 6515                            cx,
 6516                        );
 6517                        self.request_autoscroll(Autoscroll::fit(), cx);
 6518                    }
 6519                }
 6520            }
 6521            InlineCompletion::Edit { edits, .. } => {
 6522                if let Some(provider) = self.edit_prediction_provider() {
 6523                    provider.accept(cx);
 6524                }
 6525
 6526                // Store the transaction ID and selections before applying the edit
 6527                let transaction_id_prev =
 6528                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
 6529
 6530                let snapshot = self.buffer.read(cx).snapshot(cx);
 6531                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6532
 6533                self.buffer.update(cx, |buffer, cx| {
 6534                    buffer.edit(edits.iter().cloned(), None, cx)
 6535                });
 6536
 6537                self.change_selections(None, window, cx, |s| {
 6538                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6539                });
 6540
 6541                let selections = self.selections.disjoint_anchors();
 6542                if let Some(transaction_id_now) =
 6543                    self.buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
 6544                {
 6545                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6546                    if has_new_transaction {
 6547                        self.selection_history
 6548                            .insert_transaction(transaction_id_now, selections);
 6549                    }
 6550                }
 6551
 6552                self.update_visible_inline_completion(window, cx);
 6553                if self.active_inline_completion.is_none() {
 6554                    self.refresh_inline_completion(true, true, window, cx);
 6555                }
 6556
 6557                cx.notify();
 6558            }
 6559        }
 6560
 6561        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6562    }
 6563
 6564    pub fn accept_partial_inline_completion(
 6565        &mut self,
 6566        _: &AcceptPartialEditPrediction,
 6567        window: &mut Window,
 6568        cx: &mut Context<Self>,
 6569    ) {
 6570        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6571            return;
 6572        };
 6573        if self.selections.count() != 1 {
 6574            return;
 6575        }
 6576
 6577        self.report_inline_completion_event(
 6578            active_inline_completion.completion_id.clone(),
 6579            true,
 6580            cx,
 6581        );
 6582
 6583        match &active_inline_completion.completion {
 6584            InlineCompletion::Move { target, .. } => {
 6585                let target = *target;
 6586                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6587                    selections.select_anchor_ranges([target..target]);
 6588                });
 6589            }
 6590            InlineCompletion::Edit { edits, .. } => {
 6591                // Find an insertion that starts at the cursor position.
 6592                let snapshot = self.buffer.read(cx).snapshot(cx);
 6593                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6594                let insertion = edits.iter().find_map(|(range, text)| {
 6595                    let range = range.to_offset(&snapshot);
 6596                    if range.is_empty() && range.start == cursor_offset {
 6597                        Some(text)
 6598                    } else {
 6599                        None
 6600                    }
 6601                });
 6602
 6603                if let Some(text) = insertion {
 6604                    let mut partial_completion = text
 6605                        .chars()
 6606                        .by_ref()
 6607                        .take_while(|c| c.is_alphabetic())
 6608                        .collect::<String>();
 6609                    if partial_completion.is_empty() {
 6610                        partial_completion = text
 6611                            .chars()
 6612                            .by_ref()
 6613                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6614                            .collect::<String>();
 6615                    }
 6616
 6617                    cx.emit(EditorEvent::InputHandled {
 6618                        utf16_range_to_replace: None,
 6619                        text: partial_completion.clone().into(),
 6620                    });
 6621
 6622                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6623
 6624                    self.refresh_inline_completion(true, true, window, cx);
 6625                    cx.notify();
 6626                } else {
 6627                    self.accept_edit_prediction(&Default::default(), window, cx);
 6628                }
 6629            }
 6630        }
 6631    }
 6632
 6633    fn discard_inline_completion(
 6634        &mut self,
 6635        should_report_inline_completion_event: bool,
 6636        cx: &mut Context<Self>,
 6637    ) -> bool {
 6638        if should_report_inline_completion_event {
 6639            let completion_id = self
 6640                .active_inline_completion
 6641                .as_ref()
 6642                .and_then(|active_completion| active_completion.completion_id.clone());
 6643
 6644            self.report_inline_completion_event(completion_id, false, cx);
 6645        }
 6646
 6647        if let Some(provider) = self.edit_prediction_provider() {
 6648            provider.discard(cx);
 6649        }
 6650
 6651        self.take_active_inline_completion(cx)
 6652    }
 6653
 6654    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6655        let Some(provider) = self.edit_prediction_provider() else {
 6656            return;
 6657        };
 6658
 6659        let Some((_, buffer, _)) = self
 6660            .buffer
 6661            .read(cx)
 6662            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6663        else {
 6664            return;
 6665        };
 6666
 6667        let extension = buffer
 6668            .read(cx)
 6669            .file()
 6670            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6671
 6672        let event_type = match accepted {
 6673            true => "Edit Prediction Accepted",
 6674            false => "Edit Prediction Discarded",
 6675        };
 6676        telemetry::event!(
 6677            event_type,
 6678            provider = provider.name(),
 6679            prediction_id = id,
 6680            suggestion_accepted = accepted,
 6681            file_extension = extension,
 6682        );
 6683    }
 6684
 6685    pub fn has_active_inline_completion(&self) -> bool {
 6686        self.active_inline_completion.is_some()
 6687    }
 6688
 6689    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6690        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6691            return false;
 6692        };
 6693
 6694        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6695        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6696        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6697        true
 6698    }
 6699
 6700    /// Returns true when we're displaying the edit prediction popover below the cursor
 6701    /// like we are not previewing and the LSP autocomplete menu is visible
 6702    /// or we are in `when_holding_modifier` mode.
 6703    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6704        if self.edit_prediction_preview_is_active()
 6705            || !self.show_edit_predictions_in_menu()
 6706            || !self.edit_predictions_enabled()
 6707        {
 6708            return false;
 6709        }
 6710
 6711        if self.has_visible_completions_menu() {
 6712            return true;
 6713        }
 6714
 6715        has_completion && self.edit_prediction_requires_modifier()
 6716    }
 6717
 6718    fn handle_modifiers_changed(
 6719        &mut self,
 6720        modifiers: Modifiers,
 6721        position_map: &PositionMap,
 6722        window: &mut Window,
 6723        cx: &mut Context<Self>,
 6724    ) {
 6725        if self.show_edit_predictions_in_menu() {
 6726            self.update_edit_prediction_preview(&modifiers, window, cx);
 6727        }
 6728
 6729        self.update_selection_mode(&modifiers, position_map, window, cx);
 6730
 6731        let mouse_position = window.mouse_position();
 6732        if !position_map.text_hitbox.is_hovered(window) {
 6733            return;
 6734        }
 6735
 6736        self.update_hovered_link(
 6737            position_map.point_for_position(mouse_position),
 6738            &position_map.snapshot,
 6739            modifiers,
 6740            window,
 6741            cx,
 6742        )
 6743    }
 6744
 6745    fn update_selection_mode(
 6746        &mut self,
 6747        modifiers: &Modifiers,
 6748        position_map: &PositionMap,
 6749        window: &mut Window,
 6750        cx: &mut Context<Self>,
 6751    ) {
 6752        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6753            return;
 6754        }
 6755
 6756        let mouse_position = window.mouse_position();
 6757        let point_for_position = position_map.point_for_position(mouse_position);
 6758        let position = point_for_position.previous_valid;
 6759
 6760        self.select(
 6761            SelectPhase::BeginColumnar {
 6762                position,
 6763                reset: false,
 6764                goal_column: point_for_position.exact_unclipped.column(),
 6765            },
 6766            window,
 6767            cx,
 6768        );
 6769    }
 6770
 6771    fn update_edit_prediction_preview(
 6772        &mut self,
 6773        modifiers: &Modifiers,
 6774        window: &mut Window,
 6775        cx: &mut Context<Self>,
 6776    ) {
 6777        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6778        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6779            return;
 6780        };
 6781
 6782        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6783            if matches!(
 6784                self.edit_prediction_preview,
 6785                EditPredictionPreview::Inactive { .. }
 6786            ) {
 6787                self.edit_prediction_preview = EditPredictionPreview::Active {
 6788                    previous_scroll_position: None,
 6789                    since: Instant::now(),
 6790                };
 6791
 6792                self.update_visible_inline_completion(window, cx);
 6793                cx.notify();
 6794            }
 6795        } else if let EditPredictionPreview::Active {
 6796            previous_scroll_position,
 6797            since,
 6798        } = self.edit_prediction_preview
 6799        {
 6800            if let (Some(previous_scroll_position), Some(position_map)) =
 6801                (previous_scroll_position, self.last_position_map.as_ref())
 6802            {
 6803                self.set_scroll_position(
 6804                    previous_scroll_position
 6805                        .scroll_position(&position_map.snapshot.display_snapshot),
 6806                    window,
 6807                    cx,
 6808                );
 6809            }
 6810
 6811            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6812                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6813            };
 6814            self.clear_row_highlights::<EditPredictionPreview>();
 6815            self.update_visible_inline_completion(window, cx);
 6816            cx.notify();
 6817        }
 6818    }
 6819
 6820    fn update_visible_inline_completion(
 6821        &mut self,
 6822        _window: &mut Window,
 6823        cx: &mut Context<Self>,
 6824    ) -> Option<()> {
 6825        let selection = self.selections.newest_anchor();
 6826        let cursor = selection.head();
 6827        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6828        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6829        let excerpt_id = cursor.excerpt_id;
 6830
 6831        let show_in_menu = self.show_edit_predictions_in_menu();
 6832        let completions_menu_has_precedence = !show_in_menu
 6833            && (self.context_menu.borrow().is_some()
 6834                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6835
 6836        if completions_menu_has_precedence
 6837            || !offset_selection.is_empty()
 6838            || self
 6839                .active_inline_completion
 6840                .as_ref()
 6841                .map_or(false, |completion| {
 6842                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6843                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6844                    !invalidation_range.contains(&offset_selection.head())
 6845                })
 6846        {
 6847            self.discard_inline_completion(false, cx);
 6848            return None;
 6849        }
 6850
 6851        self.take_active_inline_completion(cx);
 6852        let Some(provider) = self.edit_prediction_provider() else {
 6853            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6854            return None;
 6855        };
 6856
 6857        let (buffer, cursor_buffer_position) =
 6858            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6859
 6860        self.edit_prediction_settings =
 6861            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6862
 6863        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 6864
 6865        if self.edit_prediction_indent_conflict {
 6866            let cursor_point = cursor.to_point(&multibuffer);
 6867
 6868            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 6869
 6870            if let Some((_, indent)) = indents.iter().next() {
 6871                if indent.len == cursor_point.column {
 6872                    self.edit_prediction_indent_conflict = false;
 6873                }
 6874            }
 6875        }
 6876
 6877        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 6878        let edits = inline_completion
 6879            .edits
 6880            .into_iter()
 6881            .flat_map(|(range, new_text)| {
 6882                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 6883                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 6884                Some((start..end, new_text))
 6885            })
 6886            .collect::<Vec<_>>();
 6887        if edits.is_empty() {
 6888            return None;
 6889        }
 6890
 6891        let first_edit_start = edits.first().unwrap().0.start;
 6892        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 6893        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 6894
 6895        let last_edit_end = edits.last().unwrap().0.end;
 6896        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 6897        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 6898
 6899        let cursor_row = cursor.to_point(&multibuffer).row;
 6900
 6901        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 6902
 6903        let mut inlay_ids = Vec::new();
 6904        let invalidation_row_range;
 6905        let move_invalidation_row_range = if cursor_row < edit_start_row {
 6906            Some(cursor_row..edit_end_row)
 6907        } else if cursor_row > edit_end_row {
 6908            Some(edit_start_row..cursor_row)
 6909        } else {
 6910            None
 6911        };
 6912        let is_move =
 6913            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 6914        let completion = if is_move {
 6915            invalidation_row_range =
 6916                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 6917            let target = first_edit_start;
 6918            InlineCompletion::Move { target, snapshot }
 6919        } else {
 6920            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 6921                && !self.inline_completions_hidden_for_vim_mode;
 6922
 6923            if show_completions_in_buffer {
 6924                if edits
 6925                    .iter()
 6926                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 6927                {
 6928                    let mut inlays = Vec::new();
 6929                    for (range, new_text) in &edits {
 6930                        let inlay = Inlay::inline_completion(
 6931                            post_inc(&mut self.next_inlay_id),
 6932                            range.start,
 6933                            new_text.as_str(),
 6934                        );
 6935                        inlay_ids.push(inlay.id);
 6936                        inlays.push(inlay);
 6937                    }
 6938
 6939                    self.splice_inlays(&[], inlays, cx);
 6940                } else {
 6941                    let background_color = cx.theme().status().deleted_background;
 6942                    self.highlight_text::<InlineCompletionHighlight>(
 6943                        edits.iter().map(|(range, _)| range.clone()).collect(),
 6944                        HighlightStyle {
 6945                            background_color: Some(background_color),
 6946                            ..Default::default()
 6947                        },
 6948                        cx,
 6949                    );
 6950                }
 6951            }
 6952
 6953            invalidation_row_range = edit_start_row..edit_end_row;
 6954
 6955            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 6956                if provider.show_tab_accept_marker() {
 6957                    EditDisplayMode::TabAccept
 6958                } else {
 6959                    EditDisplayMode::Inline
 6960                }
 6961            } else {
 6962                EditDisplayMode::DiffPopover
 6963            };
 6964
 6965            InlineCompletion::Edit {
 6966                edits,
 6967                edit_preview: inline_completion.edit_preview,
 6968                display_mode,
 6969                snapshot,
 6970            }
 6971        };
 6972
 6973        let invalidation_range = multibuffer
 6974            .anchor_before(Point::new(invalidation_row_range.start, 0))
 6975            ..multibuffer.anchor_after(Point::new(
 6976                invalidation_row_range.end,
 6977                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 6978            ));
 6979
 6980        self.stale_inline_completion_in_menu = None;
 6981        self.active_inline_completion = Some(InlineCompletionState {
 6982            inlay_ids,
 6983            completion,
 6984            completion_id: inline_completion.id,
 6985            invalidation_range,
 6986        });
 6987
 6988        cx.notify();
 6989
 6990        Some(())
 6991    }
 6992
 6993    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 6994        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 6995    }
 6996
 6997    fn clear_tasks(&mut self) {
 6998        self.tasks.clear()
 6999    }
 7000
 7001    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7002        if self.tasks.insert(key, value).is_some() {
 7003            // This case should hopefully be rare, but just in case...
 7004            log::error!(
 7005                "multiple different run targets found on a single line, only the last target will be rendered"
 7006            )
 7007        }
 7008    }
 7009
 7010    /// Get all display points of breakpoints that will be rendered within editor
 7011    ///
 7012    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7013    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7014    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7015    fn active_breakpoints(
 7016        &self,
 7017        range: Range<DisplayRow>,
 7018        window: &mut Window,
 7019        cx: &mut Context<Self>,
 7020    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7021        let mut breakpoint_display_points = HashMap::default();
 7022
 7023        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7024            return breakpoint_display_points;
 7025        };
 7026
 7027        let snapshot = self.snapshot(window, cx);
 7028
 7029        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7030        let Some(project) = self.project.as_ref() else {
 7031            return breakpoint_display_points;
 7032        };
 7033
 7034        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7035            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7036
 7037        for (buffer_snapshot, range, excerpt_id) in
 7038            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7039        {
 7040            let Some(buffer) = project.read_with(cx, |this, cx| {
 7041                this.buffer_for_id(buffer_snapshot.remote_id(), cx)
 7042            }) else {
 7043                continue;
 7044            };
 7045            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7046                &buffer,
 7047                Some(
 7048                    buffer_snapshot.anchor_before(range.start)
 7049                        ..buffer_snapshot.anchor_after(range.end),
 7050                ),
 7051                buffer_snapshot,
 7052                cx,
 7053            );
 7054            for (breakpoint, state) in breakpoints {
 7055                let multi_buffer_anchor =
 7056                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7057                let position = multi_buffer_anchor
 7058                    .to_point(&multi_buffer_snapshot)
 7059                    .to_display_point(&snapshot);
 7060
 7061                breakpoint_display_points.insert(
 7062                    position.row(),
 7063                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7064                );
 7065            }
 7066        }
 7067
 7068        breakpoint_display_points
 7069    }
 7070
 7071    fn breakpoint_context_menu(
 7072        &self,
 7073        anchor: Anchor,
 7074        window: &mut Window,
 7075        cx: &mut Context<Self>,
 7076    ) -> Entity<ui::ContextMenu> {
 7077        let weak_editor = cx.weak_entity();
 7078        let focus_handle = self.focus_handle(cx);
 7079
 7080        let row = self
 7081            .buffer
 7082            .read(cx)
 7083            .snapshot(cx)
 7084            .summary_for_anchor::<Point>(&anchor)
 7085            .row;
 7086
 7087        let breakpoint = self
 7088            .breakpoint_at_row(row, window, cx)
 7089            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7090
 7091        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7092            "Edit Log Breakpoint"
 7093        } else {
 7094            "Set Log Breakpoint"
 7095        };
 7096
 7097        let condition_breakpoint_msg = if breakpoint
 7098            .as_ref()
 7099            .is_some_and(|bp| bp.1.condition.is_some())
 7100        {
 7101            "Edit Condition Breakpoint"
 7102        } else {
 7103            "Set Condition Breakpoint"
 7104        };
 7105
 7106        let hit_condition_breakpoint_msg = if breakpoint
 7107            .as_ref()
 7108            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7109        {
 7110            "Edit Hit Condition Breakpoint"
 7111        } else {
 7112            "Set Hit Condition Breakpoint"
 7113        };
 7114
 7115        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7116            "Unset Breakpoint"
 7117        } else {
 7118            "Set Breakpoint"
 7119        };
 7120
 7121        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7122            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7123
 7124        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7125            BreakpointState::Enabled => Some("Disable"),
 7126            BreakpointState::Disabled => Some("Enable"),
 7127        });
 7128
 7129        let (anchor, breakpoint) =
 7130            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7131
 7132        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7133            menu.on_blur_subscription(Subscription::new(|| {}))
 7134                .context(focus_handle)
 7135                .when(run_to_cursor, |this| {
 7136                    let weak_editor = weak_editor.clone();
 7137                    this.entry("Run to cursor", None, move |window, cx| {
 7138                        weak_editor
 7139                            .update(cx, |editor, cx| {
 7140                                editor.change_selections(None, window, cx, |s| {
 7141                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7142                                });
 7143                            })
 7144                            .ok();
 7145
 7146                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7147                    })
 7148                    .separator()
 7149                })
 7150                .when_some(toggle_state_msg, |this, msg| {
 7151                    this.entry(msg, None, {
 7152                        let weak_editor = weak_editor.clone();
 7153                        let breakpoint = breakpoint.clone();
 7154                        move |_window, cx| {
 7155                            weak_editor
 7156                                .update(cx, |this, cx| {
 7157                                    this.edit_breakpoint_at_anchor(
 7158                                        anchor,
 7159                                        breakpoint.as_ref().clone(),
 7160                                        BreakpointEditAction::InvertState,
 7161                                        cx,
 7162                                    );
 7163                                })
 7164                                .log_err();
 7165                        }
 7166                    })
 7167                })
 7168                .entry(set_breakpoint_msg, None, {
 7169                    let weak_editor = weak_editor.clone();
 7170                    let breakpoint = breakpoint.clone();
 7171                    move |_window, cx| {
 7172                        weak_editor
 7173                            .update(cx, |this, cx| {
 7174                                this.edit_breakpoint_at_anchor(
 7175                                    anchor,
 7176                                    breakpoint.as_ref().clone(),
 7177                                    BreakpointEditAction::Toggle,
 7178                                    cx,
 7179                                );
 7180                            })
 7181                            .log_err();
 7182                    }
 7183                })
 7184                .entry(log_breakpoint_msg, None, {
 7185                    let breakpoint = breakpoint.clone();
 7186                    let weak_editor = weak_editor.clone();
 7187                    move |window, cx| {
 7188                        weak_editor
 7189                            .update(cx, |this, cx| {
 7190                                this.add_edit_breakpoint_block(
 7191                                    anchor,
 7192                                    breakpoint.as_ref(),
 7193                                    BreakpointPromptEditAction::Log,
 7194                                    window,
 7195                                    cx,
 7196                                );
 7197                            })
 7198                            .log_err();
 7199                    }
 7200                })
 7201                .entry(condition_breakpoint_msg, None, {
 7202                    let breakpoint = breakpoint.clone();
 7203                    let weak_editor = weak_editor.clone();
 7204                    move |window, cx| {
 7205                        weak_editor
 7206                            .update(cx, |this, cx| {
 7207                                this.add_edit_breakpoint_block(
 7208                                    anchor,
 7209                                    breakpoint.as_ref(),
 7210                                    BreakpointPromptEditAction::Condition,
 7211                                    window,
 7212                                    cx,
 7213                                );
 7214                            })
 7215                            .log_err();
 7216                    }
 7217                })
 7218                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7219                    weak_editor
 7220                        .update(cx, |this, cx| {
 7221                            this.add_edit_breakpoint_block(
 7222                                anchor,
 7223                                breakpoint.as_ref(),
 7224                                BreakpointPromptEditAction::HitCondition,
 7225                                window,
 7226                                cx,
 7227                            );
 7228                        })
 7229                        .log_err();
 7230                })
 7231        })
 7232    }
 7233
 7234    fn render_breakpoint(
 7235        &self,
 7236        position: Anchor,
 7237        row: DisplayRow,
 7238        breakpoint: &Breakpoint,
 7239        state: Option<BreakpointSessionState>,
 7240        cx: &mut Context<Self>,
 7241    ) -> IconButton {
 7242        let is_rejected = state.is_some_and(|s| !s.verified);
 7243        // Is it a breakpoint that shows up when hovering over gutter?
 7244        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7245            (false, false),
 7246            |PhantomBreakpointIndicator {
 7247                 is_active,
 7248                 display_row,
 7249                 collides_with_existing_breakpoint,
 7250             }| {
 7251                (
 7252                    is_active && display_row == row,
 7253                    collides_with_existing_breakpoint,
 7254                )
 7255            },
 7256        );
 7257
 7258        let (color, icon) = {
 7259            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7260                (false, false) => ui::IconName::DebugBreakpoint,
 7261                (true, false) => ui::IconName::DebugLogBreakpoint,
 7262                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7263                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7264            };
 7265
 7266            let color = if is_phantom {
 7267                Color::Hint
 7268            } else if is_rejected {
 7269                Color::Disabled
 7270            } else {
 7271                Color::Debugger
 7272            };
 7273
 7274            (color, icon)
 7275        };
 7276
 7277        let breakpoint = Arc::from(breakpoint.clone());
 7278
 7279        let alt_as_text = gpui::Keystroke {
 7280            modifiers: Modifiers::secondary_key(),
 7281            ..Default::default()
 7282        };
 7283        let primary_action_text = if breakpoint.is_disabled() {
 7284            "Enable breakpoint"
 7285        } else if is_phantom && !collides_with_existing {
 7286            "Set breakpoint"
 7287        } else {
 7288            "Unset breakpoint"
 7289        };
 7290        let focus_handle = self.focus_handle.clone();
 7291
 7292        let meta = if is_rejected {
 7293            SharedString::from("No executable code is associated with this line.")
 7294        } else if collides_with_existing && !breakpoint.is_disabled() {
 7295            SharedString::from(format!(
 7296                "{alt_as_text}-click to disable,\nright-click for more options."
 7297            ))
 7298        } else {
 7299            SharedString::from("Right-click for more options.")
 7300        };
 7301        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7302            .icon_size(IconSize::XSmall)
 7303            .size(ui::ButtonSize::None)
 7304            .when(is_rejected, |this| {
 7305                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7306            })
 7307            .icon_color(color)
 7308            .style(ButtonStyle::Transparent)
 7309            .on_click(cx.listener({
 7310                let breakpoint = breakpoint.clone();
 7311
 7312                move |editor, event: &ClickEvent, window, cx| {
 7313                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7314                        BreakpointEditAction::InvertState
 7315                    } else {
 7316                        BreakpointEditAction::Toggle
 7317                    };
 7318
 7319                    window.focus(&editor.focus_handle(cx));
 7320                    editor.edit_breakpoint_at_anchor(
 7321                        position,
 7322                        breakpoint.as_ref().clone(),
 7323                        edit_action,
 7324                        cx,
 7325                    );
 7326                }
 7327            }))
 7328            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7329                editor.set_breakpoint_context_menu(
 7330                    row,
 7331                    Some(position),
 7332                    event.down.position,
 7333                    window,
 7334                    cx,
 7335                );
 7336            }))
 7337            .tooltip(move |window, cx| {
 7338                Tooltip::with_meta_in(
 7339                    primary_action_text,
 7340                    Some(&ToggleBreakpoint),
 7341                    meta.clone(),
 7342                    &focus_handle,
 7343                    window,
 7344                    cx,
 7345                )
 7346            })
 7347    }
 7348
 7349    fn build_tasks_context(
 7350        project: &Entity<Project>,
 7351        buffer: &Entity<Buffer>,
 7352        buffer_row: u32,
 7353        tasks: &Arc<RunnableTasks>,
 7354        cx: &mut Context<Self>,
 7355    ) -> Task<Option<task::TaskContext>> {
 7356        let position = Point::new(buffer_row, tasks.column);
 7357        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7358        let location = Location {
 7359            buffer: buffer.clone(),
 7360            range: range_start..range_start,
 7361        };
 7362        // Fill in the environmental variables from the tree-sitter captures
 7363        let mut captured_task_variables = TaskVariables::default();
 7364        for (capture_name, value) in tasks.extra_variables.clone() {
 7365            captured_task_variables.insert(
 7366                task::VariableName::Custom(capture_name.into()),
 7367                value.clone(),
 7368            );
 7369        }
 7370        project.update(cx, |project, cx| {
 7371            project.task_store().update(cx, |task_store, cx| {
 7372                task_store.task_context_for_location(captured_task_variables, location, cx)
 7373            })
 7374        })
 7375    }
 7376
 7377    pub fn spawn_nearest_task(
 7378        &mut self,
 7379        action: &SpawnNearestTask,
 7380        window: &mut Window,
 7381        cx: &mut Context<Self>,
 7382    ) {
 7383        let Some((workspace, _)) = self.workspace.clone() else {
 7384            return;
 7385        };
 7386        let Some(project) = self.project.clone() else {
 7387            return;
 7388        };
 7389
 7390        // Try to find a closest, enclosing node using tree-sitter that has a
 7391        // task
 7392        let Some((buffer, buffer_row, tasks)) = self
 7393            .find_enclosing_node_task(cx)
 7394            // Or find the task that's closest in row-distance.
 7395            .or_else(|| self.find_closest_task(cx))
 7396        else {
 7397            return;
 7398        };
 7399
 7400        let reveal_strategy = action.reveal;
 7401        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7402        cx.spawn_in(window, async move |_, cx| {
 7403            let context = task_context.await?;
 7404            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7405
 7406            let resolved = &mut resolved_task.resolved;
 7407            resolved.reveal = reveal_strategy;
 7408
 7409            workspace
 7410                .update_in(cx, |workspace, window, cx| {
 7411                    workspace.schedule_resolved_task(
 7412                        task_source_kind,
 7413                        resolved_task,
 7414                        false,
 7415                        window,
 7416                        cx,
 7417                    );
 7418                })
 7419                .ok()
 7420        })
 7421        .detach();
 7422    }
 7423
 7424    fn find_closest_task(
 7425        &mut self,
 7426        cx: &mut Context<Self>,
 7427    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7428        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7429
 7430        let ((buffer_id, row), tasks) = self
 7431            .tasks
 7432            .iter()
 7433            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7434
 7435        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7436        let tasks = Arc::new(tasks.to_owned());
 7437        Some((buffer, *row, tasks))
 7438    }
 7439
 7440    fn find_enclosing_node_task(
 7441        &mut self,
 7442        cx: &mut Context<Self>,
 7443    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7444        let snapshot = self.buffer.read(cx).snapshot(cx);
 7445        let offset = self.selections.newest::<usize>(cx).head();
 7446        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7447        let buffer_id = excerpt.buffer().remote_id();
 7448
 7449        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7450        let mut cursor = layer.node().walk();
 7451
 7452        while cursor.goto_first_child_for_byte(offset).is_some() {
 7453            if cursor.node().end_byte() == offset {
 7454                cursor.goto_next_sibling();
 7455            }
 7456        }
 7457
 7458        // Ascend to the smallest ancestor that contains the range and has a task.
 7459        loop {
 7460            let node = cursor.node();
 7461            let node_range = node.byte_range();
 7462            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7463
 7464            // Check if this node contains our offset
 7465            if node_range.start <= offset && node_range.end >= offset {
 7466                // If it contains offset, check for task
 7467                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7468                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7469                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7470                }
 7471            }
 7472
 7473            if !cursor.goto_parent() {
 7474                break;
 7475            }
 7476        }
 7477        None
 7478    }
 7479
 7480    fn render_run_indicator(
 7481        &self,
 7482        _style: &EditorStyle,
 7483        is_active: bool,
 7484        row: DisplayRow,
 7485        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7486        cx: &mut Context<Self>,
 7487    ) -> IconButton {
 7488        let color = Color::Muted;
 7489        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7490
 7491        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7492            .shape(ui::IconButtonShape::Square)
 7493            .icon_size(IconSize::XSmall)
 7494            .icon_color(color)
 7495            .toggle_state(is_active)
 7496            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7497                let quick_launch = e.down.button == MouseButton::Left;
 7498                window.focus(&editor.focus_handle(cx));
 7499                editor.toggle_code_actions(
 7500                    &ToggleCodeActions {
 7501                        deployed_from_indicator: Some(row),
 7502                        quick_launch,
 7503                    },
 7504                    window,
 7505                    cx,
 7506                );
 7507            }))
 7508            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7509                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7510            }))
 7511    }
 7512
 7513    pub fn context_menu_visible(&self) -> bool {
 7514        !self.edit_prediction_preview_is_active()
 7515            && self
 7516                .context_menu
 7517                .borrow()
 7518                .as_ref()
 7519                .map_or(false, |menu| menu.visible())
 7520    }
 7521
 7522    fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7523        self.context_menu
 7524            .borrow()
 7525            .as_ref()
 7526            .map(|menu| menu.origin())
 7527    }
 7528
 7529    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7530        self.context_menu_options = Some(options);
 7531    }
 7532
 7533    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7534    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7535
 7536    fn render_edit_prediction_popover(
 7537        &mut self,
 7538        text_bounds: &Bounds<Pixels>,
 7539        content_origin: gpui::Point<Pixels>,
 7540        right_margin: Pixels,
 7541        editor_snapshot: &EditorSnapshot,
 7542        visible_row_range: Range<DisplayRow>,
 7543        scroll_top: f32,
 7544        scroll_bottom: f32,
 7545        line_layouts: &[LineWithInvisibles],
 7546        line_height: Pixels,
 7547        scroll_pixel_position: gpui::Point<Pixels>,
 7548        newest_selection_head: Option<DisplayPoint>,
 7549        editor_width: Pixels,
 7550        style: &EditorStyle,
 7551        window: &mut Window,
 7552        cx: &mut App,
 7553    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7554        if self.mode().is_minimap() {
 7555            return None;
 7556        }
 7557        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7558
 7559        if self.edit_prediction_visible_in_cursor_popover(true) {
 7560            return None;
 7561        }
 7562
 7563        match &active_inline_completion.completion {
 7564            InlineCompletion::Move { target, .. } => {
 7565                let target_display_point = target.to_display_point(editor_snapshot);
 7566
 7567                if self.edit_prediction_requires_modifier() {
 7568                    if !self.edit_prediction_preview_is_active() {
 7569                        return None;
 7570                    }
 7571
 7572                    self.render_edit_prediction_modifier_jump_popover(
 7573                        text_bounds,
 7574                        content_origin,
 7575                        visible_row_range,
 7576                        line_layouts,
 7577                        line_height,
 7578                        scroll_pixel_position,
 7579                        newest_selection_head,
 7580                        target_display_point,
 7581                        window,
 7582                        cx,
 7583                    )
 7584                } else {
 7585                    self.render_edit_prediction_eager_jump_popover(
 7586                        text_bounds,
 7587                        content_origin,
 7588                        editor_snapshot,
 7589                        visible_row_range,
 7590                        scroll_top,
 7591                        scroll_bottom,
 7592                        line_height,
 7593                        scroll_pixel_position,
 7594                        target_display_point,
 7595                        editor_width,
 7596                        window,
 7597                        cx,
 7598                    )
 7599                }
 7600            }
 7601            InlineCompletion::Edit {
 7602                display_mode: EditDisplayMode::Inline,
 7603                ..
 7604            } => None,
 7605            InlineCompletion::Edit {
 7606                display_mode: EditDisplayMode::TabAccept,
 7607                edits,
 7608                ..
 7609            } => {
 7610                let range = &edits.first()?.0;
 7611                let target_display_point = range.end.to_display_point(editor_snapshot);
 7612
 7613                self.render_edit_prediction_end_of_line_popover(
 7614                    "Accept",
 7615                    editor_snapshot,
 7616                    visible_row_range,
 7617                    target_display_point,
 7618                    line_height,
 7619                    scroll_pixel_position,
 7620                    content_origin,
 7621                    editor_width,
 7622                    window,
 7623                    cx,
 7624                )
 7625            }
 7626            InlineCompletion::Edit {
 7627                edits,
 7628                edit_preview,
 7629                display_mode: EditDisplayMode::DiffPopover,
 7630                snapshot,
 7631            } => self.render_edit_prediction_diff_popover(
 7632                text_bounds,
 7633                content_origin,
 7634                right_margin,
 7635                editor_snapshot,
 7636                visible_row_range,
 7637                line_layouts,
 7638                line_height,
 7639                scroll_pixel_position,
 7640                newest_selection_head,
 7641                editor_width,
 7642                style,
 7643                edits,
 7644                edit_preview,
 7645                snapshot,
 7646                window,
 7647                cx,
 7648            ),
 7649        }
 7650    }
 7651
 7652    fn render_edit_prediction_modifier_jump_popover(
 7653        &mut self,
 7654        text_bounds: &Bounds<Pixels>,
 7655        content_origin: gpui::Point<Pixels>,
 7656        visible_row_range: Range<DisplayRow>,
 7657        line_layouts: &[LineWithInvisibles],
 7658        line_height: Pixels,
 7659        scroll_pixel_position: gpui::Point<Pixels>,
 7660        newest_selection_head: Option<DisplayPoint>,
 7661        target_display_point: DisplayPoint,
 7662        window: &mut Window,
 7663        cx: &mut App,
 7664    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7665        let scrolled_content_origin =
 7666            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7667
 7668        const SCROLL_PADDING_Y: Pixels = px(12.);
 7669
 7670        if target_display_point.row() < visible_row_range.start {
 7671            return self.render_edit_prediction_scroll_popover(
 7672                |_| SCROLL_PADDING_Y,
 7673                IconName::ArrowUp,
 7674                visible_row_range,
 7675                line_layouts,
 7676                newest_selection_head,
 7677                scrolled_content_origin,
 7678                window,
 7679                cx,
 7680            );
 7681        } else if target_display_point.row() >= visible_row_range.end {
 7682            return self.render_edit_prediction_scroll_popover(
 7683                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7684                IconName::ArrowDown,
 7685                visible_row_range,
 7686                line_layouts,
 7687                newest_selection_head,
 7688                scrolled_content_origin,
 7689                window,
 7690                cx,
 7691            );
 7692        }
 7693
 7694        const POLE_WIDTH: Pixels = px(2.);
 7695
 7696        let line_layout =
 7697            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7698        let target_column = target_display_point.column() as usize;
 7699
 7700        let target_x = line_layout.x_for_index(target_column);
 7701        let target_y =
 7702            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7703
 7704        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7705
 7706        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7707        border_color.l += 0.001;
 7708
 7709        let mut element = v_flex()
 7710            .items_end()
 7711            .when(flag_on_right, |el| el.items_start())
 7712            .child(if flag_on_right {
 7713                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7714                    .rounded_bl(px(0.))
 7715                    .rounded_tl(px(0.))
 7716                    .border_l_2()
 7717                    .border_color(border_color)
 7718            } else {
 7719                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7720                    .rounded_br(px(0.))
 7721                    .rounded_tr(px(0.))
 7722                    .border_r_2()
 7723                    .border_color(border_color)
 7724            })
 7725            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7726            .into_any();
 7727
 7728        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7729
 7730        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7731            - point(
 7732                if flag_on_right {
 7733                    POLE_WIDTH
 7734                } else {
 7735                    size.width - POLE_WIDTH
 7736                },
 7737                size.height - line_height,
 7738            );
 7739
 7740        origin.x = origin.x.max(content_origin.x);
 7741
 7742        element.prepaint_at(origin, window, cx);
 7743
 7744        Some((element, origin))
 7745    }
 7746
 7747    fn render_edit_prediction_scroll_popover(
 7748        &mut self,
 7749        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7750        scroll_icon: IconName,
 7751        visible_row_range: Range<DisplayRow>,
 7752        line_layouts: &[LineWithInvisibles],
 7753        newest_selection_head: Option<DisplayPoint>,
 7754        scrolled_content_origin: gpui::Point<Pixels>,
 7755        window: &mut Window,
 7756        cx: &mut App,
 7757    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7758        let mut element = self
 7759            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7760            .into_any();
 7761
 7762        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7763
 7764        let cursor = newest_selection_head?;
 7765        let cursor_row_layout =
 7766            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7767        let cursor_column = cursor.column() as usize;
 7768
 7769        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7770
 7771        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7772
 7773        element.prepaint_at(origin, window, cx);
 7774        Some((element, origin))
 7775    }
 7776
 7777    fn render_edit_prediction_eager_jump_popover(
 7778        &mut self,
 7779        text_bounds: &Bounds<Pixels>,
 7780        content_origin: gpui::Point<Pixels>,
 7781        editor_snapshot: &EditorSnapshot,
 7782        visible_row_range: Range<DisplayRow>,
 7783        scroll_top: f32,
 7784        scroll_bottom: f32,
 7785        line_height: Pixels,
 7786        scroll_pixel_position: gpui::Point<Pixels>,
 7787        target_display_point: DisplayPoint,
 7788        editor_width: Pixels,
 7789        window: &mut Window,
 7790        cx: &mut App,
 7791    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7792        if target_display_point.row().as_f32() < scroll_top {
 7793            let mut element = self
 7794                .render_edit_prediction_line_popover(
 7795                    "Jump to Edit",
 7796                    Some(IconName::ArrowUp),
 7797                    window,
 7798                    cx,
 7799                )?
 7800                .into_any();
 7801
 7802            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7803            let offset = point(
 7804                (text_bounds.size.width - size.width) / 2.,
 7805                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7806            );
 7807
 7808            let origin = text_bounds.origin + offset;
 7809            element.prepaint_at(origin, window, cx);
 7810            Some((element, origin))
 7811        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7812            let mut element = self
 7813                .render_edit_prediction_line_popover(
 7814                    "Jump to Edit",
 7815                    Some(IconName::ArrowDown),
 7816                    window,
 7817                    cx,
 7818                )?
 7819                .into_any();
 7820
 7821            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7822            let offset = point(
 7823                (text_bounds.size.width - size.width) / 2.,
 7824                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7825            );
 7826
 7827            let origin = text_bounds.origin + offset;
 7828            element.prepaint_at(origin, window, cx);
 7829            Some((element, origin))
 7830        } else {
 7831            self.render_edit_prediction_end_of_line_popover(
 7832                "Jump to Edit",
 7833                editor_snapshot,
 7834                visible_row_range,
 7835                target_display_point,
 7836                line_height,
 7837                scroll_pixel_position,
 7838                content_origin,
 7839                editor_width,
 7840                window,
 7841                cx,
 7842            )
 7843        }
 7844    }
 7845
 7846    fn render_edit_prediction_end_of_line_popover(
 7847        self: &mut Editor,
 7848        label: &'static str,
 7849        editor_snapshot: &EditorSnapshot,
 7850        visible_row_range: Range<DisplayRow>,
 7851        target_display_point: DisplayPoint,
 7852        line_height: Pixels,
 7853        scroll_pixel_position: gpui::Point<Pixels>,
 7854        content_origin: gpui::Point<Pixels>,
 7855        editor_width: Pixels,
 7856        window: &mut Window,
 7857        cx: &mut App,
 7858    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7859        let target_line_end = DisplayPoint::new(
 7860            target_display_point.row(),
 7861            editor_snapshot.line_len(target_display_point.row()),
 7862        );
 7863
 7864        let mut element = self
 7865            .render_edit_prediction_line_popover(label, None, window, cx)?
 7866            .into_any();
 7867
 7868        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7869
 7870        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 7871
 7872        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 7873        let mut origin = start_point
 7874            + line_origin
 7875            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 7876        origin.x = origin.x.max(content_origin.x);
 7877
 7878        let max_x = content_origin.x + editor_width - size.width;
 7879
 7880        if origin.x > max_x {
 7881            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 7882
 7883            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 7884                origin.y += offset;
 7885                IconName::ArrowUp
 7886            } else {
 7887                origin.y -= offset;
 7888                IconName::ArrowDown
 7889            };
 7890
 7891            element = self
 7892                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 7893                .into_any();
 7894
 7895            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7896
 7897            origin.x = content_origin.x + editor_width - size.width - px(2.);
 7898        }
 7899
 7900        element.prepaint_at(origin, window, cx);
 7901        Some((element, origin))
 7902    }
 7903
 7904    fn render_edit_prediction_diff_popover(
 7905        self: &Editor,
 7906        text_bounds: &Bounds<Pixels>,
 7907        content_origin: gpui::Point<Pixels>,
 7908        right_margin: Pixels,
 7909        editor_snapshot: &EditorSnapshot,
 7910        visible_row_range: Range<DisplayRow>,
 7911        line_layouts: &[LineWithInvisibles],
 7912        line_height: Pixels,
 7913        scroll_pixel_position: gpui::Point<Pixels>,
 7914        newest_selection_head: Option<DisplayPoint>,
 7915        editor_width: Pixels,
 7916        style: &EditorStyle,
 7917        edits: &Vec<(Range<Anchor>, String)>,
 7918        edit_preview: &Option<language::EditPreview>,
 7919        snapshot: &language::BufferSnapshot,
 7920        window: &mut Window,
 7921        cx: &mut App,
 7922    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7923        let edit_start = edits
 7924            .first()
 7925            .unwrap()
 7926            .0
 7927            .start
 7928            .to_display_point(editor_snapshot);
 7929        let edit_end = edits
 7930            .last()
 7931            .unwrap()
 7932            .0
 7933            .end
 7934            .to_display_point(editor_snapshot);
 7935
 7936        let is_visible = visible_row_range.contains(&edit_start.row())
 7937            || visible_row_range.contains(&edit_end.row());
 7938        if !is_visible {
 7939            return None;
 7940        }
 7941
 7942        let highlighted_edits =
 7943            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 7944
 7945        let styled_text = highlighted_edits.to_styled_text(&style.text);
 7946        let line_count = highlighted_edits.text.lines().count();
 7947
 7948        const BORDER_WIDTH: Pixels = px(1.);
 7949
 7950        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 7951        let has_keybind = keybind.is_some();
 7952
 7953        let mut element = h_flex()
 7954            .items_start()
 7955            .child(
 7956                h_flex()
 7957                    .bg(cx.theme().colors().editor_background)
 7958                    .border(BORDER_WIDTH)
 7959                    .shadow_sm()
 7960                    .border_color(cx.theme().colors().border)
 7961                    .rounded_l_lg()
 7962                    .when(line_count > 1, |el| el.rounded_br_lg())
 7963                    .pr_1()
 7964                    .child(styled_text),
 7965            )
 7966            .child(
 7967                h_flex()
 7968                    .h(line_height + BORDER_WIDTH * 2.)
 7969                    .px_1p5()
 7970                    .gap_1()
 7971                    // Workaround: For some reason, there's a gap if we don't do this
 7972                    .ml(-BORDER_WIDTH)
 7973                    .shadow(smallvec![gpui::BoxShadow {
 7974                        color: gpui::black().opacity(0.05),
 7975                        offset: point(px(1.), px(1.)),
 7976                        blur_radius: px(2.),
 7977                        spread_radius: px(0.),
 7978                    }])
 7979                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 7980                    .border(BORDER_WIDTH)
 7981                    .border_color(cx.theme().colors().border)
 7982                    .rounded_r_lg()
 7983                    .id("edit_prediction_diff_popover_keybind")
 7984                    .when(!has_keybind, |el| {
 7985                        let status_colors = cx.theme().status();
 7986
 7987                        el.bg(status_colors.error_background)
 7988                            .border_color(status_colors.error.opacity(0.6))
 7989                            .child(Icon::new(IconName::Info).color(Color::Error))
 7990                            .cursor_default()
 7991                            .hoverable_tooltip(move |_window, cx| {
 7992                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 7993                            })
 7994                    })
 7995                    .children(keybind),
 7996            )
 7997            .into_any();
 7998
 7999        let longest_row =
 8000            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8001        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8002            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8003        } else {
 8004            layout_line(
 8005                longest_row,
 8006                editor_snapshot,
 8007                style,
 8008                editor_width,
 8009                |_| false,
 8010                window,
 8011                cx,
 8012            )
 8013            .width
 8014        };
 8015
 8016        let viewport_bounds =
 8017            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8018                right: -right_margin,
 8019                ..Default::default()
 8020            });
 8021
 8022        let x_after_longest =
 8023            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8024                - scroll_pixel_position.x;
 8025
 8026        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8027
 8028        // Fully visible if it can be displayed within the window (allow overlapping other
 8029        // panes). However, this is only allowed if the popover starts within text_bounds.
 8030        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8031            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8032
 8033        let mut origin = if can_position_to_the_right {
 8034            point(
 8035                x_after_longest,
 8036                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8037                    - scroll_pixel_position.y,
 8038            )
 8039        } else {
 8040            let cursor_row = newest_selection_head.map(|head| head.row());
 8041            let above_edit = edit_start
 8042                .row()
 8043                .0
 8044                .checked_sub(line_count as u32)
 8045                .map(DisplayRow);
 8046            let below_edit = Some(edit_end.row() + 1);
 8047            let above_cursor =
 8048                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8049            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8050
 8051            // Place the edit popover adjacent to the edit if there is a location
 8052            // available that is onscreen and does not obscure the cursor. Otherwise,
 8053            // place it adjacent to the cursor.
 8054            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8055                .into_iter()
 8056                .flatten()
 8057                .find(|&start_row| {
 8058                    let end_row = start_row + line_count as u32;
 8059                    visible_row_range.contains(&start_row)
 8060                        && visible_row_range.contains(&end_row)
 8061                        && cursor_row.map_or(true, |cursor_row| {
 8062                            !((start_row..end_row).contains(&cursor_row))
 8063                        })
 8064                })?;
 8065
 8066            content_origin
 8067                + point(
 8068                    -scroll_pixel_position.x,
 8069                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8070                )
 8071        };
 8072
 8073        origin.x -= BORDER_WIDTH;
 8074
 8075        window.defer_draw(element, origin, 1);
 8076
 8077        // Do not return an element, since it will already be drawn due to defer_draw.
 8078        None
 8079    }
 8080
 8081    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8082        px(30.)
 8083    }
 8084
 8085    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8086        if self.read_only(cx) {
 8087            cx.theme().players().read_only()
 8088        } else {
 8089            self.style.as_ref().unwrap().local_player
 8090        }
 8091    }
 8092
 8093    fn render_edit_prediction_accept_keybind(
 8094        &self,
 8095        window: &mut Window,
 8096        cx: &App,
 8097    ) -> Option<AnyElement> {
 8098        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8099        let accept_keystroke = accept_binding.keystroke()?;
 8100
 8101        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8102
 8103        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8104            Color::Accent
 8105        } else {
 8106            Color::Muted
 8107        };
 8108
 8109        h_flex()
 8110            .px_0p5()
 8111            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8112            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8113            .text_size(TextSize::XSmall.rems(cx))
 8114            .child(h_flex().children(ui::render_modifiers(
 8115                &accept_keystroke.modifiers,
 8116                PlatformStyle::platform(),
 8117                Some(modifiers_color),
 8118                Some(IconSize::XSmall.rems().into()),
 8119                true,
 8120            )))
 8121            .when(is_platform_style_mac, |parent| {
 8122                parent.child(accept_keystroke.key.clone())
 8123            })
 8124            .when(!is_platform_style_mac, |parent| {
 8125                parent.child(
 8126                    Key::new(
 8127                        util::capitalize(&accept_keystroke.key),
 8128                        Some(Color::Default),
 8129                    )
 8130                    .size(Some(IconSize::XSmall.rems().into())),
 8131                )
 8132            })
 8133            .into_any()
 8134            .into()
 8135    }
 8136
 8137    fn render_edit_prediction_line_popover(
 8138        &self,
 8139        label: impl Into<SharedString>,
 8140        icon: Option<IconName>,
 8141        window: &mut Window,
 8142        cx: &App,
 8143    ) -> Option<Stateful<Div>> {
 8144        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8145
 8146        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8147        let has_keybind = keybind.is_some();
 8148
 8149        let result = h_flex()
 8150            .id("ep-line-popover")
 8151            .py_0p5()
 8152            .pl_1()
 8153            .pr(padding_right)
 8154            .gap_1()
 8155            .rounded_md()
 8156            .border_1()
 8157            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8158            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8159            .shadow_sm()
 8160            .when(!has_keybind, |el| {
 8161                let status_colors = cx.theme().status();
 8162
 8163                el.bg(status_colors.error_background)
 8164                    .border_color(status_colors.error.opacity(0.6))
 8165                    .pl_2()
 8166                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8167                    .cursor_default()
 8168                    .hoverable_tooltip(move |_window, cx| {
 8169                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8170                    })
 8171            })
 8172            .children(keybind)
 8173            .child(
 8174                Label::new(label)
 8175                    .size(LabelSize::Small)
 8176                    .when(!has_keybind, |el| {
 8177                        el.color(cx.theme().status().error.into()).strikethrough()
 8178                    }),
 8179            )
 8180            .when(!has_keybind, |el| {
 8181                el.child(
 8182                    h_flex().ml_1().child(
 8183                        Icon::new(IconName::Info)
 8184                            .size(IconSize::Small)
 8185                            .color(cx.theme().status().error.into()),
 8186                    ),
 8187                )
 8188            })
 8189            .when_some(icon, |element, icon| {
 8190                element.child(
 8191                    div()
 8192                        .mt(px(1.5))
 8193                        .child(Icon::new(icon).size(IconSize::Small)),
 8194                )
 8195            });
 8196
 8197        Some(result)
 8198    }
 8199
 8200    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8201        let accent_color = cx.theme().colors().text_accent;
 8202        let editor_bg_color = cx.theme().colors().editor_background;
 8203        editor_bg_color.blend(accent_color.opacity(0.1))
 8204    }
 8205
 8206    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8207        let accent_color = cx.theme().colors().text_accent;
 8208        let editor_bg_color = cx.theme().colors().editor_background;
 8209        editor_bg_color.blend(accent_color.opacity(0.6))
 8210    }
 8211
 8212    fn render_edit_prediction_cursor_popover(
 8213        &self,
 8214        min_width: Pixels,
 8215        max_width: Pixels,
 8216        cursor_point: Point,
 8217        style: &EditorStyle,
 8218        accept_keystroke: Option<&gpui::Keystroke>,
 8219        _window: &Window,
 8220        cx: &mut Context<Editor>,
 8221    ) -> Option<AnyElement> {
 8222        let provider = self.edit_prediction_provider.as_ref()?;
 8223
 8224        if provider.provider.needs_terms_acceptance(cx) {
 8225            return Some(
 8226                h_flex()
 8227                    .min_w(min_width)
 8228                    .flex_1()
 8229                    .px_2()
 8230                    .py_1()
 8231                    .gap_3()
 8232                    .elevation_2(cx)
 8233                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8234                    .id("accept-terms")
 8235                    .cursor_pointer()
 8236                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8237                    .on_click(cx.listener(|this, _event, window, cx| {
 8238                        cx.stop_propagation();
 8239                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8240                        window.dispatch_action(
 8241                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8242                            cx,
 8243                        );
 8244                    }))
 8245                    .child(
 8246                        h_flex()
 8247                            .flex_1()
 8248                            .gap_2()
 8249                            .child(Icon::new(IconName::ZedPredict))
 8250                            .child(Label::new("Accept Terms of Service"))
 8251                            .child(div().w_full())
 8252                            .child(
 8253                                Icon::new(IconName::ArrowUpRight)
 8254                                    .color(Color::Muted)
 8255                                    .size(IconSize::Small),
 8256                            )
 8257                            .into_any_element(),
 8258                    )
 8259                    .into_any(),
 8260            );
 8261        }
 8262
 8263        let is_refreshing = provider.provider.is_refreshing(cx);
 8264
 8265        fn pending_completion_container() -> Div {
 8266            h_flex()
 8267                .h_full()
 8268                .flex_1()
 8269                .gap_2()
 8270                .child(Icon::new(IconName::ZedPredict))
 8271        }
 8272
 8273        let completion = match &self.active_inline_completion {
 8274            Some(prediction) => {
 8275                if !self.has_visible_completions_menu() {
 8276                    const RADIUS: Pixels = px(6.);
 8277                    const BORDER_WIDTH: Pixels = px(1.);
 8278
 8279                    return Some(
 8280                        h_flex()
 8281                            .elevation_2(cx)
 8282                            .border(BORDER_WIDTH)
 8283                            .border_color(cx.theme().colors().border)
 8284                            .when(accept_keystroke.is_none(), |el| {
 8285                                el.border_color(cx.theme().status().error)
 8286                            })
 8287                            .rounded(RADIUS)
 8288                            .rounded_tl(px(0.))
 8289                            .overflow_hidden()
 8290                            .child(div().px_1p5().child(match &prediction.completion {
 8291                                InlineCompletion::Move { target, snapshot } => {
 8292                                    use text::ToPoint as _;
 8293                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8294                                    {
 8295                                        Icon::new(IconName::ZedPredictDown)
 8296                                    } else {
 8297                                        Icon::new(IconName::ZedPredictUp)
 8298                                    }
 8299                                }
 8300                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8301                            }))
 8302                            .child(
 8303                                h_flex()
 8304                                    .gap_1()
 8305                                    .py_1()
 8306                                    .px_2()
 8307                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8308                                    .border_l_1()
 8309                                    .border_color(cx.theme().colors().border)
 8310                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8311                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8312                                        el.child(
 8313                                            Label::new("Hold")
 8314                                                .size(LabelSize::Small)
 8315                                                .when(accept_keystroke.is_none(), |el| {
 8316                                                    el.strikethrough()
 8317                                                })
 8318                                                .line_height_style(LineHeightStyle::UiLabel),
 8319                                        )
 8320                                    })
 8321                                    .id("edit_prediction_cursor_popover_keybind")
 8322                                    .when(accept_keystroke.is_none(), |el| {
 8323                                        let status_colors = cx.theme().status();
 8324
 8325                                        el.bg(status_colors.error_background)
 8326                                            .border_color(status_colors.error.opacity(0.6))
 8327                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8328                                            .cursor_default()
 8329                                            .hoverable_tooltip(move |_window, cx| {
 8330                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8331                                                    .into()
 8332                                            })
 8333                                    })
 8334                                    .when_some(
 8335                                        accept_keystroke.as_ref(),
 8336                                        |el, accept_keystroke| {
 8337                                            el.child(h_flex().children(ui::render_modifiers(
 8338                                                &accept_keystroke.modifiers,
 8339                                                PlatformStyle::platform(),
 8340                                                Some(Color::Default),
 8341                                                Some(IconSize::XSmall.rems().into()),
 8342                                                false,
 8343                                            )))
 8344                                        },
 8345                                    ),
 8346                            )
 8347                            .into_any(),
 8348                    );
 8349                }
 8350
 8351                self.render_edit_prediction_cursor_popover_preview(
 8352                    prediction,
 8353                    cursor_point,
 8354                    style,
 8355                    cx,
 8356                )?
 8357            }
 8358
 8359            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8360                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8361                    stale_completion,
 8362                    cursor_point,
 8363                    style,
 8364                    cx,
 8365                )?,
 8366
 8367                None => {
 8368                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8369                }
 8370            },
 8371
 8372            None => pending_completion_container().child(Label::new("No Prediction")),
 8373        };
 8374
 8375        let completion = if is_refreshing {
 8376            completion
 8377                .with_animation(
 8378                    "loading-completion",
 8379                    Animation::new(Duration::from_secs(2))
 8380                        .repeat()
 8381                        .with_easing(pulsating_between(0.4, 0.8)),
 8382                    |label, delta| label.opacity(delta),
 8383                )
 8384                .into_any_element()
 8385        } else {
 8386            completion.into_any_element()
 8387        };
 8388
 8389        let has_completion = self.active_inline_completion.is_some();
 8390
 8391        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8392        Some(
 8393            h_flex()
 8394                .min_w(min_width)
 8395                .max_w(max_width)
 8396                .flex_1()
 8397                .elevation_2(cx)
 8398                .border_color(cx.theme().colors().border)
 8399                .child(
 8400                    div()
 8401                        .flex_1()
 8402                        .py_1()
 8403                        .px_2()
 8404                        .overflow_hidden()
 8405                        .child(completion),
 8406                )
 8407                .when_some(accept_keystroke, |el, accept_keystroke| {
 8408                    if !accept_keystroke.modifiers.modified() {
 8409                        return el;
 8410                    }
 8411
 8412                    el.child(
 8413                        h_flex()
 8414                            .h_full()
 8415                            .border_l_1()
 8416                            .rounded_r_lg()
 8417                            .border_color(cx.theme().colors().border)
 8418                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8419                            .gap_1()
 8420                            .py_1()
 8421                            .px_2()
 8422                            .child(
 8423                                h_flex()
 8424                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8425                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8426                                    .child(h_flex().children(ui::render_modifiers(
 8427                                        &accept_keystroke.modifiers,
 8428                                        PlatformStyle::platform(),
 8429                                        Some(if !has_completion {
 8430                                            Color::Muted
 8431                                        } else {
 8432                                            Color::Default
 8433                                        }),
 8434                                        None,
 8435                                        false,
 8436                                    ))),
 8437                            )
 8438                            .child(Label::new("Preview").into_any_element())
 8439                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8440                    )
 8441                })
 8442                .into_any(),
 8443        )
 8444    }
 8445
 8446    fn render_edit_prediction_cursor_popover_preview(
 8447        &self,
 8448        completion: &InlineCompletionState,
 8449        cursor_point: Point,
 8450        style: &EditorStyle,
 8451        cx: &mut Context<Editor>,
 8452    ) -> Option<Div> {
 8453        use text::ToPoint as _;
 8454
 8455        fn render_relative_row_jump(
 8456            prefix: impl Into<String>,
 8457            current_row: u32,
 8458            target_row: u32,
 8459        ) -> Div {
 8460            let (row_diff, arrow) = if target_row < current_row {
 8461                (current_row - target_row, IconName::ArrowUp)
 8462            } else {
 8463                (target_row - current_row, IconName::ArrowDown)
 8464            };
 8465
 8466            h_flex()
 8467                .child(
 8468                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8469                        .color(Color::Muted)
 8470                        .size(LabelSize::Small),
 8471                )
 8472                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8473        }
 8474
 8475        match &completion.completion {
 8476            InlineCompletion::Move {
 8477                target, snapshot, ..
 8478            } => Some(
 8479                h_flex()
 8480                    .px_2()
 8481                    .gap_2()
 8482                    .flex_1()
 8483                    .child(
 8484                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8485                            Icon::new(IconName::ZedPredictDown)
 8486                        } else {
 8487                            Icon::new(IconName::ZedPredictUp)
 8488                        },
 8489                    )
 8490                    .child(Label::new("Jump to Edit")),
 8491            ),
 8492
 8493            InlineCompletion::Edit {
 8494                edits,
 8495                edit_preview,
 8496                snapshot,
 8497                display_mode: _,
 8498            } => {
 8499                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8500
 8501                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8502                    &snapshot,
 8503                    &edits,
 8504                    edit_preview.as_ref()?,
 8505                    true,
 8506                    cx,
 8507                )
 8508                .first_line_preview();
 8509
 8510                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8511                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8512
 8513                let preview = h_flex()
 8514                    .gap_1()
 8515                    .min_w_16()
 8516                    .child(styled_text)
 8517                    .when(has_more_lines, |parent| parent.child(""));
 8518
 8519                let left = if first_edit_row != cursor_point.row {
 8520                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8521                        .into_any_element()
 8522                } else {
 8523                    Icon::new(IconName::ZedPredict).into_any_element()
 8524                };
 8525
 8526                Some(
 8527                    h_flex()
 8528                        .h_full()
 8529                        .flex_1()
 8530                        .gap_2()
 8531                        .pr_1()
 8532                        .overflow_x_hidden()
 8533                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8534                        .child(left)
 8535                        .child(preview),
 8536                )
 8537            }
 8538        }
 8539    }
 8540
 8541    fn render_context_menu(
 8542        &self,
 8543        style: &EditorStyle,
 8544        max_height_in_lines: u32,
 8545        window: &mut Window,
 8546        cx: &mut Context<Editor>,
 8547    ) -> Option<AnyElement> {
 8548        let menu = self.context_menu.borrow();
 8549        let menu = menu.as_ref()?;
 8550        if !menu.visible() {
 8551            return None;
 8552        };
 8553        Some(menu.render(style, max_height_in_lines, window, cx))
 8554    }
 8555
 8556    fn render_context_menu_aside(
 8557        &mut self,
 8558        max_size: Size<Pixels>,
 8559        window: &mut Window,
 8560        cx: &mut Context<Editor>,
 8561    ) -> Option<AnyElement> {
 8562        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8563            if menu.visible() {
 8564                menu.render_aside(self, max_size, window, cx)
 8565            } else {
 8566                None
 8567            }
 8568        })
 8569    }
 8570
 8571    fn hide_context_menu(
 8572        &mut self,
 8573        window: &mut Window,
 8574        cx: &mut Context<Self>,
 8575    ) -> Option<CodeContextMenu> {
 8576        cx.notify();
 8577        self.completion_tasks.clear();
 8578        let context_menu = self.context_menu.borrow_mut().take();
 8579        self.stale_inline_completion_in_menu.take();
 8580        self.update_visible_inline_completion(window, cx);
 8581        context_menu
 8582    }
 8583
 8584    fn show_snippet_choices(
 8585        &mut self,
 8586        choices: &Vec<String>,
 8587        selection: Range<Anchor>,
 8588        cx: &mut Context<Self>,
 8589    ) {
 8590        if selection.start.buffer_id.is_none() {
 8591            return;
 8592        }
 8593        let buffer_id = selection.start.buffer_id.unwrap();
 8594        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8595        let id = post_inc(&mut self.next_completion_id);
 8596        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8597
 8598        if let Some(buffer) = buffer {
 8599            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8600                CompletionsMenu::new_snippet_choices(
 8601                    id,
 8602                    true,
 8603                    choices,
 8604                    selection,
 8605                    buffer,
 8606                    snippet_sort_order,
 8607                ),
 8608            ));
 8609        }
 8610    }
 8611
 8612    pub fn insert_snippet(
 8613        &mut self,
 8614        insertion_ranges: &[Range<usize>],
 8615        snippet: Snippet,
 8616        window: &mut Window,
 8617        cx: &mut Context<Self>,
 8618    ) -> Result<()> {
 8619        struct Tabstop<T> {
 8620            is_end_tabstop: bool,
 8621            ranges: Vec<Range<T>>,
 8622            choices: Option<Vec<String>>,
 8623        }
 8624
 8625        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8626            let snippet_text: Arc<str> = snippet.text.clone().into();
 8627            let edits = insertion_ranges
 8628                .iter()
 8629                .cloned()
 8630                .map(|range| (range, snippet_text.clone()));
 8631            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8632
 8633            let snapshot = &*buffer.read(cx);
 8634            let snippet = &snippet;
 8635            snippet
 8636                .tabstops
 8637                .iter()
 8638                .map(|tabstop| {
 8639                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8640                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8641                    });
 8642                    let mut tabstop_ranges = tabstop
 8643                        .ranges
 8644                        .iter()
 8645                        .flat_map(|tabstop_range| {
 8646                            let mut delta = 0_isize;
 8647                            insertion_ranges.iter().map(move |insertion_range| {
 8648                                let insertion_start = insertion_range.start as isize + delta;
 8649                                delta +=
 8650                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8651
 8652                                let start = ((insertion_start + tabstop_range.start) as usize)
 8653                                    .min(snapshot.len());
 8654                                let end = ((insertion_start + tabstop_range.end) as usize)
 8655                                    .min(snapshot.len());
 8656                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8657                            })
 8658                        })
 8659                        .collect::<Vec<_>>();
 8660                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8661
 8662                    Tabstop {
 8663                        is_end_tabstop,
 8664                        ranges: tabstop_ranges,
 8665                        choices: tabstop.choices.clone(),
 8666                    }
 8667                })
 8668                .collect::<Vec<_>>()
 8669        });
 8670        if let Some(tabstop) = tabstops.first() {
 8671            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8672                s.select_ranges(tabstop.ranges.iter().cloned());
 8673            });
 8674
 8675            if let Some(choices) = &tabstop.choices {
 8676                if let Some(selection) = tabstop.ranges.first() {
 8677                    self.show_snippet_choices(choices, selection.clone(), cx)
 8678                }
 8679            }
 8680
 8681            // If we're already at the last tabstop and it's at the end of the snippet,
 8682            // we're done, we don't need to keep the state around.
 8683            if !tabstop.is_end_tabstop {
 8684                let choices = tabstops
 8685                    .iter()
 8686                    .map(|tabstop| tabstop.choices.clone())
 8687                    .collect();
 8688
 8689                let ranges = tabstops
 8690                    .into_iter()
 8691                    .map(|tabstop| tabstop.ranges)
 8692                    .collect::<Vec<_>>();
 8693
 8694                self.snippet_stack.push(SnippetState {
 8695                    active_index: 0,
 8696                    ranges,
 8697                    choices,
 8698                });
 8699            }
 8700
 8701            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8702            if self.autoclose_regions.is_empty() {
 8703                let snapshot = self.buffer.read(cx).snapshot(cx);
 8704                for selection in &mut self.selections.all::<Point>(cx) {
 8705                    let selection_head = selection.head();
 8706                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8707                        continue;
 8708                    };
 8709
 8710                    let mut bracket_pair = None;
 8711                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8712                    let prev_chars = snapshot
 8713                        .reversed_chars_at(selection_head)
 8714                        .collect::<String>();
 8715                    for (pair, enabled) in scope.brackets() {
 8716                        if enabled
 8717                            && pair.close
 8718                            && prev_chars.starts_with(pair.start.as_str())
 8719                            && next_chars.starts_with(pair.end.as_str())
 8720                        {
 8721                            bracket_pair = Some(pair.clone());
 8722                            break;
 8723                        }
 8724                    }
 8725                    if let Some(pair) = bracket_pair {
 8726                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8727                        let autoclose_enabled =
 8728                            self.use_autoclose && snapshot_settings.use_autoclose;
 8729                        if autoclose_enabled {
 8730                            let start = snapshot.anchor_after(selection_head);
 8731                            let end = snapshot.anchor_after(selection_head);
 8732                            self.autoclose_regions.push(AutocloseRegion {
 8733                                selection_id: selection.id,
 8734                                range: start..end,
 8735                                pair,
 8736                            });
 8737                        }
 8738                    }
 8739                }
 8740            }
 8741        }
 8742        Ok(())
 8743    }
 8744
 8745    pub fn move_to_next_snippet_tabstop(
 8746        &mut self,
 8747        window: &mut Window,
 8748        cx: &mut Context<Self>,
 8749    ) -> bool {
 8750        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8751    }
 8752
 8753    pub fn move_to_prev_snippet_tabstop(
 8754        &mut self,
 8755        window: &mut Window,
 8756        cx: &mut Context<Self>,
 8757    ) -> bool {
 8758        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8759    }
 8760
 8761    pub fn move_to_snippet_tabstop(
 8762        &mut self,
 8763        bias: Bias,
 8764        window: &mut Window,
 8765        cx: &mut Context<Self>,
 8766    ) -> bool {
 8767        if let Some(mut snippet) = self.snippet_stack.pop() {
 8768            match bias {
 8769                Bias::Left => {
 8770                    if snippet.active_index > 0 {
 8771                        snippet.active_index -= 1;
 8772                    } else {
 8773                        self.snippet_stack.push(snippet);
 8774                        return false;
 8775                    }
 8776                }
 8777                Bias::Right => {
 8778                    if snippet.active_index + 1 < snippet.ranges.len() {
 8779                        snippet.active_index += 1;
 8780                    } else {
 8781                        self.snippet_stack.push(snippet);
 8782                        return false;
 8783                    }
 8784                }
 8785            }
 8786            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8787                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8788                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8789                });
 8790
 8791                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8792                    if let Some(selection) = current_ranges.first() {
 8793                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8794                    }
 8795                }
 8796
 8797                // If snippet state is not at the last tabstop, push it back on the stack
 8798                if snippet.active_index + 1 < snippet.ranges.len() {
 8799                    self.snippet_stack.push(snippet);
 8800                }
 8801                return true;
 8802            }
 8803        }
 8804
 8805        false
 8806    }
 8807
 8808    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8809        self.transact(window, cx, |this, window, cx| {
 8810            this.select_all(&SelectAll, window, cx);
 8811            this.insert("", window, cx);
 8812        });
 8813    }
 8814
 8815    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8816        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8817        self.transact(window, cx, |this, window, cx| {
 8818            this.select_autoclose_pair(window, cx);
 8819            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8820            if !this.linked_edit_ranges.is_empty() {
 8821                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8822                let snapshot = this.buffer.read(cx).snapshot(cx);
 8823
 8824                for selection in selections.iter() {
 8825                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8826                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8827                    if selection_start.buffer_id != selection_end.buffer_id {
 8828                        continue;
 8829                    }
 8830                    if let Some(ranges) =
 8831                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8832                    {
 8833                        for (buffer, entries) in ranges {
 8834                            linked_ranges.entry(buffer).or_default().extend(entries);
 8835                        }
 8836                    }
 8837                }
 8838            }
 8839
 8840            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 8841            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 8842            for selection in &mut selections {
 8843                if selection.is_empty() {
 8844                    let old_head = selection.head();
 8845                    let mut new_head =
 8846                        movement::left(&display_map, old_head.to_display_point(&display_map))
 8847                            .to_point(&display_map);
 8848                    if let Some((buffer, line_buffer_range)) = display_map
 8849                        .buffer_snapshot
 8850                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 8851                    {
 8852                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 8853                        let indent_len = match indent_size.kind {
 8854                            IndentKind::Space => {
 8855                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 8856                            }
 8857                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 8858                        };
 8859                        if old_head.column <= indent_size.len && old_head.column > 0 {
 8860                            let indent_len = indent_len.get();
 8861                            new_head = cmp::min(
 8862                                new_head,
 8863                                MultiBufferPoint::new(
 8864                                    old_head.row,
 8865                                    ((old_head.column - 1) / indent_len) * indent_len,
 8866                                ),
 8867                            );
 8868                        }
 8869                    }
 8870
 8871                    selection.set_head(new_head, SelectionGoal::None);
 8872                }
 8873            }
 8874
 8875            this.signature_help_state.set_backspace_pressed(true);
 8876            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8877                s.select(selections)
 8878            });
 8879            this.insert("", window, cx);
 8880            let empty_str: Arc<str> = Arc::from("");
 8881            for (buffer, edits) in linked_ranges {
 8882                let snapshot = buffer.read(cx).snapshot();
 8883                use text::ToPoint as TP;
 8884
 8885                let edits = edits
 8886                    .into_iter()
 8887                    .map(|range| {
 8888                        let end_point = TP::to_point(&range.end, &snapshot);
 8889                        let mut start_point = TP::to_point(&range.start, &snapshot);
 8890
 8891                        if end_point == start_point {
 8892                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 8893                                .saturating_sub(1);
 8894                            start_point =
 8895                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 8896                        };
 8897
 8898                        (start_point..end_point, empty_str.clone())
 8899                    })
 8900                    .sorted_by_key(|(range, _)| range.start)
 8901                    .collect::<Vec<_>>();
 8902                buffer.update(cx, |this, cx| {
 8903                    this.edit(edits, None, cx);
 8904                })
 8905            }
 8906            this.refresh_inline_completion(true, false, window, cx);
 8907            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 8908        });
 8909    }
 8910
 8911    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 8912        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8913        self.transact(window, cx, |this, window, cx| {
 8914            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8915                s.move_with(|map, selection| {
 8916                    if selection.is_empty() {
 8917                        let cursor = movement::right(map, selection.head());
 8918                        selection.end = cursor;
 8919                        selection.reversed = true;
 8920                        selection.goal = SelectionGoal::None;
 8921                    }
 8922                })
 8923            });
 8924            this.insert("", window, cx);
 8925            this.refresh_inline_completion(true, false, window, cx);
 8926        });
 8927    }
 8928
 8929    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 8930        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8931        if self.move_to_prev_snippet_tabstop(window, cx) {
 8932            return;
 8933        }
 8934        self.outdent(&Outdent, window, cx);
 8935    }
 8936
 8937    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 8938        if self.move_to_next_snippet_tabstop(window, cx) {
 8939            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8940            return;
 8941        }
 8942        if self.read_only(cx) {
 8943            return;
 8944        }
 8945        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8946        let mut selections = self.selections.all_adjusted(cx);
 8947        let buffer = self.buffer.read(cx);
 8948        let snapshot = buffer.snapshot(cx);
 8949        let rows_iter = selections.iter().map(|s| s.head().row);
 8950        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 8951
 8952        let has_some_cursor_in_whitespace = selections
 8953            .iter()
 8954            .filter(|selection| selection.is_empty())
 8955            .any(|selection| {
 8956                let cursor = selection.head();
 8957                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8958                cursor.column < current_indent.len
 8959            });
 8960
 8961        let mut edits = Vec::new();
 8962        let mut prev_edited_row = 0;
 8963        let mut row_delta = 0;
 8964        for selection in &mut selections {
 8965            if selection.start.row != prev_edited_row {
 8966                row_delta = 0;
 8967            }
 8968            prev_edited_row = selection.end.row;
 8969
 8970            // If the selection is non-empty, then increase the indentation of the selected lines.
 8971            if !selection.is_empty() {
 8972                row_delta =
 8973                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 8974                continue;
 8975            }
 8976
 8977            let cursor = selection.head();
 8978            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 8979            if let Some(suggested_indent) =
 8980                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 8981            {
 8982                // Don't do anything if already at suggested indent
 8983                // and there is any other cursor which is not
 8984                if has_some_cursor_in_whitespace
 8985                    && cursor.column == current_indent.len
 8986                    && current_indent.len == suggested_indent.len
 8987                {
 8988                    continue;
 8989                }
 8990
 8991                // Adjust line and move cursor to suggested indent
 8992                // if cursor is not at suggested indent
 8993                if cursor.column < suggested_indent.len
 8994                    && cursor.column <= current_indent.len
 8995                    && current_indent.len <= suggested_indent.len
 8996                {
 8997                    selection.start = Point::new(cursor.row, suggested_indent.len);
 8998                    selection.end = selection.start;
 8999                    if row_delta == 0 {
 9000                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9001                            cursor.row,
 9002                            current_indent,
 9003                            suggested_indent,
 9004                        ));
 9005                        row_delta = suggested_indent.len - current_indent.len;
 9006                    }
 9007                    continue;
 9008                }
 9009
 9010                // If current indent is more than suggested indent
 9011                // only move cursor to current indent and skip indent
 9012                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9013                    selection.start = Point::new(cursor.row, current_indent.len);
 9014                    selection.end = selection.start;
 9015                    continue;
 9016                }
 9017            }
 9018
 9019            // Otherwise, insert a hard or soft tab.
 9020            let settings = buffer.language_settings_at(cursor, cx);
 9021            let tab_size = if settings.hard_tabs {
 9022                IndentSize::tab()
 9023            } else {
 9024                let tab_size = settings.tab_size.get();
 9025                let indent_remainder = snapshot
 9026                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9027                    .flat_map(str::chars)
 9028                    .fold(row_delta % tab_size, |counter: u32, c| {
 9029                        if c == '\t' {
 9030                            0
 9031                        } else {
 9032                            (counter + 1) % tab_size
 9033                        }
 9034                    });
 9035
 9036                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9037                IndentSize::spaces(chars_to_next_tab_stop)
 9038            };
 9039            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9040            selection.end = selection.start;
 9041            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9042            row_delta += tab_size.len;
 9043        }
 9044
 9045        self.transact(window, cx, |this, window, cx| {
 9046            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9047            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9048                s.select(selections)
 9049            });
 9050            this.refresh_inline_completion(true, false, window, cx);
 9051        });
 9052    }
 9053
 9054    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9055        if self.read_only(cx) {
 9056            return;
 9057        }
 9058        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9059        let mut selections = self.selections.all::<Point>(cx);
 9060        let mut prev_edited_row = 0;
 9061        let mut row_delta = 0;
 9062        let mut edits = Vec::new();
 9063        let buffer = self.buffer.read(cx);
 9064        let snapshot = buffer.snapshot(cx);
 9065        for selection in &mut selections {
 9066            if selection.start.row != prev_edited_row {
 9067                row_delta = 0;
 9068            }
 9069            prev_edited_row = selection.end.row;
 9070
 9071            row_delta =
 9072                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9073        }
 9074
 9075        self.transact(window, cx, |this, window, cx| {
 9076            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9077            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9078                s.select(selections)
 9079            });
 9080        });
 9081    }
 9082
 9083    fn indent_selection(
 9084        buffer: &MultiBuffer,
 9085        snapshot: &MultiBufferSnapshot,
 9086        selection: &mut Selection<Point>,
 9087        edits: &mut Vec<(Range<Point>, String)>,
 9088        delta_for_start_row: u32,
 9089        cx: &App,
 9090    ) -> u32 {
 9091        let settings = buffer.language_settings_at(selection.start, cx);
 9092        let tab_size = settings.tab_size.get();
 9093        let indent_kind = if settings.hard_tabs {
 9094            IndentKind::Tab
 9095        } else {
 9096            IndentKind::Space
 9097        };
 9098        let mut start_row = selection.start.row;
 9099        let mut end_row = selection.end.row + 1;
 9100
 9101        // If a selection ends at the beginning of a line, don't indent
 9102        // that last line.
 9103        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9104            end_row -= 1;
 9105        }
 9106
 9107        // Avoid re-indenting a row that has already been indented by a
 9108        // previous selection, but still update this selection's column
 9109        // to reflect that indentation.
 9110        if delta_for_start_row > 0 {
 9111            start_row += 1;
 9112            selection.start.column += delta_for_start_row;
 9113            if selection.end.row == selection.start.row {
 9114                selection.end.column += delta_for_start_row;
 9115            }
 9116        }
 9117
 9118        let mut delta_for_end_row = 0;
 9119        let has_multiple_rows = start_row + 1 != end_row;
 9120        for row in start_row..end_row {
 9121            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9122            let indent_delta = match (current_indent.kind, indent_kind) {
 9123                (IndentKind::Space, IndentKind::Space) => {
 9124                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9125                    IndentSize::spaces(columns_to_next_tab_stop)
 9126                }
 9127                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9128                (_, IndentKind::Tab) => IndentSize::tab(),
 9129            };
 9130
 9131            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9132                0
 9133            } else {
 9134                selection.start.column
 9135            };
 9136            let row_start = Point::new(row, start);
 9137            edits.push((
 9138                row_start..row_start,
 9139                indent_delta.chars().collect::<String>(),
 9140            ));
 9141
 9142            // Update this selection's endpoints to reflect the indentation.
 9143            if row == selection.start.row {
 9144                selection.start.column += indent_delta.len;
 9145            }
 9146            if row == selection.end.row {
 9147                selection.end.column += indent_delta.len;
 9148                delta_for_end_row = indent_delta.len;
 9149            }
 9150        }
 9151
 9152        if selection.start.row == selection.end.row {
 9153            delta_for_start_row + delta_for_end_row
 9154        } else {
 9155            delta_for_end_row
 9156        }
 9157    }
 9158
 9159    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9160        if self.read_only(cx) {
 9161            return;
 9162        }
 9163        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9164        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9165        let selections = self.selections.all::<Point>(cx);
 9166        let mut deletion_ranges = Vec::new();
 9167        let mut last_outdent = None;
 9168        {
 9169            let buffer = self.buffer.read(cx);
 9170            let snapshot = buffer.snapshot(cx);
 9171            for selection in &selections {
 9172                let settings = buffer.language_settings_at(selection.start, cx);
 9173                let tab_size = settings.tab_size.get();
 9174                let mut rows = selection.spanned_rows(false, &display_map);
 9175
 9176                // Avoid re-outdenting a row that has already been outdented by a
 9177                // previous selection.
 9178                if let Some(last_row) = last_outdent {
 9179                    if last_row == rows.start {
 9180                        rows.start = rows.start.next_row();
 9181                    }
 9182                }
 9183                let has_multiple_rows = rows.len() > 1;
 9184                for row in rows.iter_rows() {
 9185                    let indent_size = snapshot.indent_size_for_line(row);
 9186                    if indent_size.len > 0 {
 9187                        let deletion_len = match indent_size.kind {
 9188                            IndentKind::Space => {
 9189                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9190                                if columns_to_prev_tab_stop == 0 {
 9191                                    tab_size
 9192                                } else {
 9193                                    columns_to_prev_tab_stop
 9194                                }
 9195                            }
 9196                            IndentKind::Tab => 1,
 9197                        };
 9198                        let start = if has_multiple_rows
 9199                            || deletion_len > selection.start.column
 9200                            || indent_size.len < selection.start.column
 9201                        {
 9202                            0
 9203                        } else {
 9204                            selection.start.column - deletion_len
 9205                        };
 9206                        deletion_ranges.push(
 9207                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9208                        );
 9209                        last_outdent = Some(row);
 9210                    }
 9211                }
 9212            }
 9213        }
 9214
 9215        self.transact(window, cx, |this, window, cx| {
 9216            this.buffer.update(cx, |buffer, cx| {
 9217                let empty_str: Arc<str> = Arc::default();
 9218                buffer.edit(
 9219                    deletion_ranges
 9220                        .into_iter()
 9221                        .map(|range| (range, empty_str.clone())),
 9222                    None,
 9223                    cx,
 9224                );
 9225            });
 9226            let selections = this.selections.all::<usize>(cx);
 9227            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9228                s.select(selections)
 9229            });
 9230        });
 9231    }
 9232
 9233    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9234        if self.read_only(cx) {
 9235            return;
 9236        }
 9237        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9238        let selections = self
 9239            .selections
 9240            .all::<usize>(cx)
 9241            .into_iter()
 9242            .map(|s| s.range());
 9243
 9244        self.transact(window, cx, |this, window, cx| {
 9245            this.buffer.update(cx, |buffer, cx| {
 9246                buffer.autoindent_ranges(selections, cx);
 9247            });
 9248            let selections = this.selections.all::<usize>(cx);
 9249            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9250                s.select(selections)
 9251            });
 9252        });
 9253    }
 9254
 9255    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9256        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9258        let selections = self.selections.all::<Point>(cx);
 9259
 9260        let mut new_cursors = Vec::new();
 9261        let mut edit_ranges = Vec::new();
 9262        let mut selections = selections.iter().peekable();
 9263        while let Some(selection) = selections.next() {
 9264            let mut rows = selection.spanned_rows(false, &display_map);
 9265            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9266
 9267            // Accumulate contiguous regions of rows that we want to delete.
 9268            while let Some(next_selection) = selections.peek() {
 9269                let next_rows = next_selection.spanned_rows(false, &display_map);
 9270                if next_rows.start <= rows.end {
 9271                    rows.end = next_rows.end;
 9272                    selections.next().unwrap();
 9273                } else {
 9274                    break;
 9275                }
 9276            }
 9277
 9278            let buffer = &display_map.buffer_snapshot;
 9279            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9280            let edit_end;
 9281            let cursor_buffer_row;
 9282            if buffer.max_point().row >= rows.end.0 {
 9283                // If there's a line after the range, delete the \n from the end of the row range
 9284                // and position the cursor on the next line.
 9285                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9286                cursor_buffer_row = rows.end;
 9287            } else {
 9288                // If there isn't a line after the range, delete the \n from the line before the
 9289                // start of the row range and position the cursor there.
 9290                edit_start = edit_start.saturating_sub(1);
 9291                edit_end = buffer.len();
 9292                cursor_buffer_row = rows.start.previous_row();
 9293            }
 9294
 9295            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9296            *cursor.column_mut() =
 9297                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9298
 9299            new_cursors.push((
 9300                selection.id,
 9301                buffer.anchor_after(cursor.to_point(&display_map)),
 9302            ));
 9303            edit_ranges.push(edit_start..edit_end);
 9304        }
 9305
 9306        self.transact(window, cx, |this, window, cx| {
 9307            let buffer = this.buffer.update(cx, |buffer, cx| {
 9308                let empty_str: Arc<str> = Arc::default();
 9309                buffer.edit(
 9310                    edit_ranges
 9311                        .into_iter()
 9312                        .map(|range| (range, empty_str.clone())),
 9313                    None,
 9314                    cx,
 9315                );
 9316                buffer.snapshot(cx)
 9317            });
 9318            let new_selections = new_cursors
 9319                .into_iter()
 9320                .map(|(id, cursor)| {
 9321                    let cursor = cursor.to_point(&buffer);
 9322                    Selection {
 9323                        id,
 9324                        start: cursor,
 9325                        end: cursor,
 9326                        reversed: false,
 9327                        goal: SelectionGoal::None,
 9328                    }
 9329                })
 9330                .collect();
 9331
 9332            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9333                s.select(new_selections);
 9334            });
 9335        });
 9336    }
 9337
 9338    pub fn join_lines_impl(
 9339        &mut self,
 9340        insert_whitespace: bool,
 9341        window: &mut Window,
 9342        cx: &mut Context<Self>,
 9343    ) {
 9344        if self.read_only(cx) {
 9345            return;
 9346        }
 9347        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9348        for selection in self.selections.all::<Point>(cx) {
 9349            let start = MultiBufferRow(selection.start.row);
 9350            // Treat single line selections as if they include the next line. Otherwise this action
 9351            // would do nothing for single line selections individual cursors.
 9352            let end = if selection.start.row == selection.end.row {
 9353                MultiBufferRow(selection.start.row + 1)
 9354            } else {
 9355                MultiBufferRow(selection.end.row)
 9356            };
 9357
 9358            if let Some(last_row_range) = row_ranges.last_mut() {
 9359                if start <= last_row_range.end {
 9360                    last_row_range.end = end;
 9361                    continue;
 9362                }
 9363            }
 9364            row_ranges.push(start..end);
 9365        }
 9366
 9367        let snapshot = self.buffer.read(cx).snapshot(cx);
 9368        let mut cursor_positions = Vec::new();
 9369        for row_range in &row_ranges {
 9370            let anchor = snapshot.anchor_before(Point::new(
 9371                row_range.end.previous_row().0,
 9372                snapshot.line_len(row_range.end.previous_row()),
 9373            ));
 9374            cursor_positions.push(anchor..anchor);
 9375        }
 9376
 9377        self.transact(window, cx, |this, window, cx| {
 9378            for row_range in row_ranges.into_iter().rev() {
 9379                for row in row_range.iter_rows().rev() {
 9380                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9381                    let next_line_row = row.next_row();
 9382                    let indent = snapshot.indent_size_for_line(next_line_row);
 9383                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9384
 9385                    let replace =
 9386                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9387                            " "
 9388                        } else {
 9389                            ""
 9390                        };
 9391
 9392                    this.buffer.update(cx, |buffer, cx| {
 9393                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9394                    });
 9395                }
 9396            }
 9397
 9398            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9399                s.select_anchor_ranges(cursor_positions)
 9400            });
 9401        });
 9402    }
 9403
 9404    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9405        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9406        self.join_lines_impl(true, window, cx);
 9407    }
 9408
 9409    pub fn sort_lines_case_sensitive(
 9410        &mut self,
 9411        _: &SortLinesCaseSensitive,
 9412        window: &mut Window,
 9413        cx: &mut Context<Self>,
 9414    ) {
 9415        self.manipulate_lines(window, cx, |lines| lines.sort())
 9416    }
 9417
 9418    pub fn sort_lines_case_insensitive(
 9419        &mut self,
 9420        _: &SortLinesCaseInsensitive,
 9421        window: &mut Window,
 9422        cx: &mut Context<Self>,
 9423    ) {
 9424        self.manipulate_lines(window, cx, |lines| {
 9425            lines.sort_by_key(|line| line.to_lowercase())
 9426        })
 9427    }
 9428
 9429    pub fn unique_lines_case_insensitive(
 9430        &mut self,
 9431        _: &UniqueLinesCaseInsensitive,
 9432        window: &mut Window,
 9433        cx: &mut Context<Self>,
 9434    ) {
 9435        self.manipulate_lines(window, cx, |lines| {
 9436            let mut seen = HashSet::default();
 9437            lines.retain(|line| seen.insert(line.to_lowercase()));
 9438        })
 9439    }
 9440
 9441    pub fn unique_lines_case_sensitive(
 9442        &mut self,
 9443        _: &UniqueLinesCaseSensitive,
 9444        window: &mut Window,
 9445        cx: &mut Context<Self>,
 9446    ) {
 9447        self.manipulate_lines(window, cx, |lines| {
 9448            let mut seen = HashSet::default();
 9449            lines.retain(|line| seen.insert(*line));
 9450        })
 9451    }
 9452
 9453    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9454        let Some(project) = self.project.clone() else {
 9455            return;
 9456        };
 9457        self.reload(project, window, cx)
 9458            .detach_and_notify_err(window, cx);
 9459    }
 9460
 9461    pub fn restore_file(
 9462        &mut self,
 9463        _: &::git::RestoreFile,
 9464        window: &mut Window,
 9465        cx: &mut Context<Self>,
 9466    ) {
 9467        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9468        let mut buffer_ids = HashSet::default();
 9469        let snapshot = self.buffer().read(cx).snapshot(cx);
 9470        for selection in self.selections.all::<usize>(cx) {
 9471            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9472        }
 9473
 9474        let buffer = self.buffer().read(cx);
 9475        let ranges = buffer_ids
 9476            .into_iter()
 9477            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9478            .collect::<Vec<_>>();
 9479
 9480        self.restore_hunks_in_ranges(ranges, window, cx);
 9481    }
 9482
 9483    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9484        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9485        let selections = self
 9486            .selections
 9487            .all(cx)
 9488            .into_iter()
 9489            .map(|s| s.range())
 9490            .collect();
 9491        self.restore_hunks_in_ranges(selections, window, cx);
 9492    }
 9493
 9494    pub fn restore_hunks_in_ranges(
 9495        &mut self,
 9496        ranges: Vec<Range<Point>>,
 9497        window: &mut Window,
 9498        cx: &mut Context<Editor>,
 9499    ) {
 9500        let mut revert_changes = HashMap::default();
 9501        let chunk_by = self
 9502            .snapshot(window, cx)
 9503            .hunks_for_ranges(ranges)
 9504            .into_iter()
 9505            .chunk_by(|hunk| hunk.buffer_id);
 9506        for (buffer_id, hunks) in &chunk_by {
 9507            let hunks = hunks.collect::<Vec<_>>();
 9508            for hunk in &hunks {
 9509                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9510            }
 9511            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9512        }
 9513        drop(chunk_by);
 9514        if !revert_changes.is_empty() {
 9515            self.transact(window, cx, |editor, window, cx| {
 9516                editor.restore(revert_changes, window, cx);
 9517            });
 9518        }
 9519    }
 9520
 9521    pub fn open_active_item_in_terminal(
 9522        &mut self,
 9523        _: &OpenInTerminal,
 9524        window: &mut Window,
 9525        cx: &mut Context<Self>,
 9526    ) {
 9527        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9528            let project_path = buffer.read(cx).project_path(cx)?;
 9529            let project = self.project.as_ref()?.read(cx);
 9530            let entry = project.entry_for_path(&project_path, cx)?;
 9531            let parent = match &entry.canonical_path {
 9532                Some(canonical_path) => canonical_path.to_path_buf(),
 9533                None => project.absolute_path(&project_path, cx)?,
 9534            }
 9535            .parent()?
 9536            .to_path_buf();
 9537            Some(parent)
 9538        }) {
 9539            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9540        }
 9541    }
 9542
 9543    fn set_breakpoint_context_menu(
 9544        &mut self,
 9545        display_row: DisplayRow,
 9546        position: Option<Anchor>,
 9547        clicked_point: gpui::Point<Pixels>,
 9548        window: &mut Window,
 9549        cx: &mut Context<Self>,
 9550    ) {
 9551        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9552            return;
 9553        }
 9554        let source = self
 9555            .buffer
 9556            .read(cx)
 9557            .snapshot(cx)
 9558            .anchor_before(Point::new(display_row.0, 0u32));
 9559
 9560        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9561
 9562        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9563            self,
 9564            source,
 9565            clicked_point,
 9566            context_menu,
 9567            window,
 9568            cx,
 9569        );
 9570    }
 9571
 9572    fn add_edit_breakpoint_block(
 9573        &mut self,
 9574        anchor: Anchor,
 9575        breakpoint: &Breakpoint,
 9576        edit_action: BreakpointPromptEditAction,
 9577        window: &mut Window,
 9578        cx: &mut Context<Self>,
 9579    ) {
 9580        let weak_editor = cx.weak_entity();
 9581        let bp_prompt = cx.new(|cx| {
 9582            BreakpointPromptEditor::new(
 9583                weak_editor,
 9584                anchor,
 9585                breakpoint.clone(),
 9586                edit_action,
 9587                window,
 9588                cx,
 9589            )
 9590        });
 9591
 9592        let height = bp_prompt.update(cx, |this, cx| {
 9593            this.prompt
 9594                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9595        });
 9596        let cloned_prompt = bp_prompt.clone();
 9597        let blocks = vec![BlockProperties {
 9598            style: BlockStyle::Sticky,
 9599            placement: BlockPlacement::Above(anchor),
 9600            height: Some(height),
 9601            render: Arc::new(move |cx| {
 9602                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9603                cloned_prompt.clone().into_any_element()
 9604            }),
 9605            priority: 0,
 9606            render_in_minimap: true,
 9607        }];
 9608
 9609        let focus_handle = bp_prompt.focus_handle(cx);
 9610        window.focus(&focus_handle);
 9611
 9612        let block_ids = self.insert_blocks(blocks, None, cx);
 9613        bp_prompt.update(cx, |prompt, _| {
 9614            prompt.add_block_ids(block_ids);
 9615        });
 9616    }
 9617
 9618    pub(crate) fn breakpoint_at_row(
 9619        &self,
 9620        row: u32,
 9621        window: &mut Window,
 9622        cx: &mut Context<Self>,
 9623    ) -> Option<(Anchor, Breakpoint)> {
 9624        let snapshot = self.snapshot(window, cx);
 9625        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9626
 9627        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9628    }
 9629
 9630    pub(crate) fn breakpoint_at_anchor(
 9631        &self,
 9632        breakpoint_position: Anchor,
 9633        snapshot: &EditorSnapshot,
 9634        cx: &mut Context<Self>,
 9635    ) -> Option<(Anchor, Breakpoint)> {
 9636        let project = self.project.clone()?;
 9637
 9638        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9639            snapshot
 9640                .buffer_snapshot
 9641                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9642        })?;
 9643
 9644        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9645        let buffer = project.read_with(cx, |project, cx| project.buffer_for_id(buffer_id, cx))?;
 9646        let buffer_snapshot = buffer.read(cx).snapshot();
 9647
 9648        let row = buffer_snapshot
 9649            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9650            .row;
 9651
 9652        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9653        let anchor_end = snapshot
 9654            .buffer_snapshot
 9655            .anchor_after(Point::new(row, line_len));
 9656
 9657        let bp = self
 9658            .breakpoint_store
 9659            .as_ref()?
 9660            .read_with(cx, |breakpoint_store, cx| {
 9661                breakpoint_store
 9662                    .breakpoints(
 9663                        &buffer,
 9664                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9665                        &buffer_snapshot,
 9666                        cx,
 9667                    )
 9668                    .next()
 9669                    .and_then(|(bp, _)| {
 9670                        let breakpoint_row = buffer_snapshot
 9671                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9672                            .row;
 9673
 9674                        if breakpoint_row == row {
 9675                            snapshot
 9676                                .buffer_snapshot
 9677                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9678                                .map(|position| (position, bp.bp.clone()))
 9679                        } else {
 9680                            None
 9681                        }
 9682                    })
 9683            });
 9684        bp
 9685    }
 9686
 9687    pub fn edit_log_breakpoint(
 9688        &mut self,
 9689        _: &EditLogBreakpoint,
 9690        window: &mut Window,
 9691        cx: &mut Context<Self>,
 9692    ) {
 9693        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9694            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9695                message: None,
 9696                state: BreakpointState::Enabled,
 9697                condition: None,
 9698                hit_condition: None,
 9699            });
 9700
 9701            self.add_edit_breakpoint_block(
 9702                anchor,
 9703                &breakpoint,
 9704                BreakpointPromptEditAction::Log,
 9705                window,
 9706                cx,
 9707            );
 9708        }
 9709    }
 9710
 9711    fn breakpoints_at_cursors(
 9712        &self,
 9713        window: &mut Window,
 9714        cx: &mut Context<Self>,
 9715    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9716        let snapshot = self.snapshot(window, cx);
 9717        let cursors = self
 9718            .selections
 9719            .disjoint_anchors()
 9720            .into_iter()
 9721            .map(|selection| {
 9722                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9723
 9724                let breakpoint_position = self
 9725                    .breakpoint_at_row(cursor_position.row, window, cx)
 9726                    .map(|bp| bp.0)
 9727                    .unwrap_or_else(|| {
 9728                        snapshot
 9729                            .display_snapshot
 9730                            .buffer_snapshot
 9731                            .anchor_after(Point::new(cursor_position.row, 0))
 9732                    });
 9733
 9734                let breakpoint = self
 9735                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9736                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9737
 9738                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9739            })
 9740            // 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.
 9741            .collect::<HashMap<Anchor, _>>();
 9742
 9743        cursors.into_iter().collect()
 9744    }
 9745
 9746    pub fn enable_breakpoint(
 9747        &mut self,
 9748        _: &crate::actions::EnableBreakpoint,
 9749        window: &mut Window,
 9750        cx: &mut Context<Self>,
 9751    ) {
 9752        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9753            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9754                continue;
 9755            };
 9756            self.edit_breakpoint_at_anchor(
 9757                anchor,
 9758                breakpoint,
 9759                BreakpointEditAction::InvertState,
 9760                cx,
 9761            );
 9762        }
 9763    }
 9764
 9765    pub fn disable_breakpoint(
 9766        &mut self,
 9767        _: &crate::actions::DisableBreakpoint,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) {
 9771        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9772            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9773                continue;
 9774            };
 9775            self.edit_breakpoint_at_anchor(
 9776                anchor,
 9777                breakpoint,
 9778                BreakpointEditAction::InvertState,
 9779                cx,
 9780            );
 9781        }
 9782    }
 9783
 9784    pub fn toggle_breakpoint(
 9785        &mut self,
 9786        _: &crate::actions::ToggleBreakpoint,
 9787        window: &mut Window,
 9788        cx: &mut Context<Self>,
 9789    ) {
 9790        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9791            if let Some(breakpoint) = breakpoint {
 9792                self.edit_breakpoint_at_anchor(
 9793                    anchor,
 9794                    breakpoint,
 9795                    BreakpointEditAction::Toggle,
 9796                    cx,
 9797                );
 9798            } else {
 9799                self.edit_breakpoint_at_anchor(
 9800                    anchor,
 9801                    Breakpoint::new_standard(),
 9802                    BreakpointEditAction::Toggle,
 9803                    cx,
 9804                );
 9805            }
 9806        }
 9807    }
 9808
 9809    pub fn edit_breakpoint_at_anchor(
 9810        &mut self,
 9811        breakpoint_position: Anchor,
 9812        breakpoint: Breakpoint,
 9813        edit_action: BreakpointEditAction,
 9814        cx: &mut Context<Self>,
 9815    ) {
 9816        let Some(breakpoint_store) = &self.breakpoint_store else {
 9817            return;
 9818        };
 9819
 9820        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9821            if breakpoint_position == Anchor::min() {
 9822                self.buffer()
 9823                    .read(cx)
 9824                    .excerpt_buffer_ids()
 9825                    .into_iter()
 9826                    .next()
 9827            } else {
 9828                None
 9829            }
 9830        }) else {
 9831            return;
 9832        };
 9833
 9834        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9835            return;
 9836        };
 9837
 9838        breakpoint_store.update(cx, |breakpoint_store, cx| {
 9839            breakpoint_store.toggle_breakpoint(
 9840                buffer,
 9841                BreakpointWithPosition {
 9842                    position: breakpoint_position.text_anchor,
 9843                    bp: breakpoint,
 9844                },
 9845                edit_action,
 9846                cx,
 9847            );
 9848        });
 9849
 9850        cx.notify();
 9851    }
 9852
 9853    #[cfg(any(test, feature = "test-support"))]
 9854    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
 9855        self.breakpoint_store.clone()
 9856    }
 9857
 9858    pub fn prepare_restore_change(
 9859        &self,
 9860        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
 9861        hunk: &MultiBufferDiffHunk,
 9862        cx: &mut App,
 9863    ) -> Option<()> {
 9864        if hunk.is_created_file() {
 9865            return None;
 9866        }
 9867        let buffer = self.buffer.read(cx);
 9868        let diff = buffer.diff_for(hunk.buffer_id)?;
 9869        let buffer = buffer.buffer(hunk.buffer_id)?;
 9870        let buffer = buffer.read(cx);
 9871        let original_text = diff
 9872            .read(cx)
 9873            .base_text()
 9874            .as_rope()
 9875            .slice(hunk.diff_base_byte_range.clone());
 9876        let buffer_snapshot = buffer.snapshot();
 9877        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
 9878        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
 9879            probe
 9880                .0
 9881                .start
 9882                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
 9883                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
 9884        }) {
 9885            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
 9886            Some(())
 9887        } else {
 9888            None
 9889        }
 9890    }
 9891
 9892    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
 9893        self.manipulate_lines(window, cx, |lines| lines.reverse())
 9894    }
 9895
 9896    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
 9897        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
 9898    }
 9899
 9900    fn manipulate_lines<Fn>(
 9901        &mut self,
 9902        window: &mut Window,
 9903        cx: &mut Context<Self>,
 9904        mut callback: Fn,
 9905    ) where
 9906        Fn: FnMut(&mut Vec<&str>),
 9907    {
 9908        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9909
 9910        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9911        let buffer = self.buffer.read(cx).snapshot(cx);
 9912
 9913        let mut edits = Vec::new();
 9914
 9915        let selections = self.selections.all::<Point>(cx);
 9916        let mut selections = selections.iter().peekable();
 9917        let mut contiguous_row_selections = Vec::new();
 9918        let mut new_selections = Vec::new();
 9919        let mut added_lines = 0;
 9920        let mut removed_lines = 0;
 9921
 9922        while let Some(selection) = selections.next() {
 9923            let (start_row, end_row) = consume_contiguous_rows(
 9924                &mut contiguous_row_selections,
 9925                selection,
 9926                &display_map,
 9927                &mut selections,
 9928            );
 9929
 9930            let start_point = Point::new(start_row.0, 0);
 9931            let end_point = Point::new(
 9932                end_row.previous_row().0,
 9933                buffer.line_len(end_row.previous_row()),
 9934            );
 9935            let text = buffer
 9936                .text_for_range(start_point..end_point)
 9937                .collect::<String>();
 9938
 9939            let mut lines = text.split('\n').collect_vec();
 9940
 9941            let lines_before = lines.len();
 9942            callback(&mut lines);
 9943            let lines_after = lines.len();
 9944
 9945            edits.push((start_point..end_point, lines.join("\n")));
 9946
 9947            // Selections must change based on added and removed line count
 9948            let start_row =
 9949                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
 9950            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
 9951            new_selections.push(Selection {
 9952                id: selection.id,
 9953                start: start_row,
 9954                end: end_row,
 9955                goal: SelectionGoal::None,
 9956                reversed: selection.reversed,
 9957            });
 9958
 9959            if lines_after > lines_before {
 9960                added_lines += lines_after - lines_before;
 9961            } else if lines_before > lines_after {
 9962                removed_lines += lines_before - lines_after;
 9963            }
 9964        }
 9965
 9966        self.transact(window, cx, |this, window, cx| {
 9967            let buffer = this.buffer.update(cx, |buffer, cx| {
 9968                buffer.edit(edits, None, cx);
 9969                buffer.snapshot(cx)
 9970            });
 9971
 9972            // Recalculate offsets on newly edited buffer
 9973            let new_selections = new_selections
 9974                .iter()
 9975                .map(|s| {
 9976                    let start_point = Point::new(s.start.0, 0);
 9977                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
 9978                    Selection {
 9979                        id: s.id,
 9980                        start: buffer.point_to_offset(start_point),
 9981                        end: buffer.point_to_offset(end_point),
 9982                        goal: s.goal,
 9983                        reversed: s.reversed,
 9984                    }
 9985                })
 9986                .collect();
 9987
 9988            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9989                s.select(new_selections);
 9990            });
 9991
 9992            this.request_autoscroll(Autoscroll::fit(), cx);
 9993        });
 9994    }
 9995
 9996    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
 9997        self.manipulate_text(window, cx, |text| {
 9998            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
 9999            if has_upper_case_characters {
10000                text.to_lowercase()
10001            } else {
10002                text.to_uppercase()
10003            }
10004        })
10005    }
10006
10007    pub fn convert_to_upper_case(
10008        &mut self,
10009        _: &ConvertToUpperCase,
10010        window: &mut Window,
10011        cx: &mut Context<Self>,
10012    ) {
10013        self.manipulate_text(window, cx, |text| text.to_uppercase())
10014    }
10015
10016    pub fn convert_to_lower_case(
10017        &mut self,
10018        _: &ConvertToLowerCase,
10019        window: &mut Window,
10020        cx: &mut Context<Self>,
10021    ) {
10022        self.manipulate_text(window, cx, |text| text.to_lowercase())
10023    }
10024
10025    pub fn convert_to_title_case(
10026        &mut self,
10027        _: &ConvertToTitleCase,
10028        window: &mut Window,
10029        cx: &mut Context<Self>,
10030    ) {
10031        self.manipulate_text(window, cx, |text| {
10032            text.split('\n')
10033                .map(|line| line.to_case(Case::Title))
10034                .join("\n")
10035        })
10036    }
10037
10038    pub fn convert_to_snake_case(
10039        &mut self,
10040        _: &ConvertToSnakeCase,
10041        window: &mut Window,
10042        cx: &mut Context<Self>,
10043    ) {
10044        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10045    }
10046
10047    pub fn convert_to_kebab_case(
10048        &mut self,
10049        _: &ConvertToKebabCase,
10050        window: &mut Window,
10051        cx: &mut Context<Self>,
10052    ) {
10053        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10054    }
10055
10056    pub fn convert_to_upper_camel_case(
10057        &mut self,
10058        _: &ConvertToUpperCamelCase,
10059        window: &mut Window,
10060        cx: &mut Context<Self>,
10061    ) {
10062        self.manipulate_text(window, cx, |text| {
10063            text.split('\n')
10064                .map(|line| line.to_case(Case::UpperCamel))
10065                .join("\n")
10066        })
10067    }
10068
10069    pub fn convert_to_lower_camel_case(
10070        &mut self,
10071        _: &ConvertToLowerCamelCase,
10072        window: &mut Window,
10073        cx: &mut Context<Self>,
10074    ) {
10075        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10076    }
10077
10078    pub fn convert_to_opposite_case(
10079        &mut self,
10080        _: &ConvertToOppositeCase,
10081        window: &mut Window,
10082        cx: &mut Context<Self>,
10083    ) {
10084        self.manipulate_text(window, cx, |text| {
10085            text.chars()
10086                .fold(String::with_capacity(text.len()), |mut t, c| {
10087                    if c.is_uppercase() {
10088                        t.extend(c.to_lowercase());
10089                    } else {
10090                        t.extend(c.to_uppercase());
10091                    }
10092                    t
10093                })
10094        })
10095    }
10096
10097    pub fn convert_to_rot13(
10098        &mut self,
10099        _: &ConvertToRot13,
10100        window: &mut Window,
10101        cx: &mut Context<Self>,
10102    ) {
10103        self.manipulate_text(window, cx, |text| {
10104            text.chars()
10105                .map(|c| match c {
10106                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10107                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10108                    _ => c,
10109                })
10110                .collect()
10111        })
10112    }
10113
10114    pub fn convert_to_rot47(
10115        &mut self,
10116        _: &ConvertToRot47,
10117        window: &mut Window,
10118        cx: &mut Context<Self>,
10119    ) {
10120        self.manipulate_text(window, cx, |text| {
10121            text.chars()
10122                .map(|c| {
10123                    let code_point = c as u32;
10124                    if code_point >= 33 && code_point <= 126 {
10125                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10126                    }
10127                    c
10128                })
10129                .collect()
10130        })
10131    }
10132
10133    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10134    where
10135        Fn: FnMut(&str) -> String,
10136    {
10137        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10138        let buffer = self.buffer.read(cx).snapshot(cx);
10139
10140        let mut new_selections = Vec::new();
10141        let mut edits = Vec::new();
10142        let mut selection_adjustment = 0i32;
10143
10144        for selection in self.selections.all::<usize>(cx) {
10145            let selection_is_empty = selection.is_empty();
10146
10147            let (start, end) = if selection_is_empty {
10148                let word_range = movement::surrounding_word(
10149                    &display_map,
10150                    selection.start.to_display_point(&display_map),
10151                );
10152                let start = word_range.start.to_offset(&display_map, Bias::Left);
10153                let end = word_range.end.to_offset(&display_map, Bias::Left);
10154                (start, end)
10155            } else {
10156                (selection.start, selection.end)
10157            };
10158
10159            let text = buffer.text_for_range(start..end).collect::<String>();
10160            let old_length = text.len() as i32;
10161            let text = callback(&text);
10162
10163            new_selections.push(Selection {
10164                start: (start as i32 - selection_adjustment) as usize,
10165                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10166                goal: SelectionGoal::None,
10167                ..selection
10168            });
10169
10170            selection_adjustment += old_length - text.len() as i32;
10171
10172            edits.push((start..end, text));
10173        }
10174
10175        self.transact(window, cx, |this, window, cx| {
10176            this.buffer.update(cx, |buffer, cx| {
10177                buffer.edit(edits, None, cx);
10178            });
10179
10180            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10181                s.select(new_selections);
10182            });
10183
10184            this.request_autoscroll(Autoscroll::fit(), cx);
10185        });
10186    }
10187
10188    pub fn duplicate(
10189        &mut self,
10190        upwards: bool,
10191        whole_lines: bool,
10192        window: &mut Window,
10193        cx: &mut Context<Self>,
10194    ) {
10195        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10196
10197        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10198        let buffer = &display_map.buffer_snapshot;
10199        let selections = self.selections.all::<Point>(cx);
10200
10201        let mut edits = Vec::new();
10202        let mut selections_iter = selections.iter().peekable();
10203        while let Some(selection) = selections_iter.next() {
10204            let mut rows = selection.spanned_rows(false, &display_map);
10205            // duplicate line-wise
10206            if whole_lines || selection.start == selection.end {
10207                // Avoid duplicating the same lines twice.
10208                while let Some(next_selection) = selections_iter.peek() {
10209                    let next_rows = next_selection.spanned_rows(false, &display_map);
10210                    if next_rows.start < rows.end {
10211                        rows.end = next_rows.end;
10212                        selections_iter.next().unwrap();
10213                    } else {
10214                        break;
10215                    }
10216                }
10217
10218                // Copy the text from the selected row region and splice it either at the start
10219                // or end of the region.
10220                let start = Point::new(rows.start.0, 0);
10221                let end = Point::new(
10222                    rows.end.previous_row().0,
10223                    buffer.line_len(rows.end.previous_row()),
10224                );
10225                let text = buffer
10226                    .text_for_range(start..end)
10227                    .chain(Some("\n"))
10228                    .collect::<String>();
10229                let insert_location = if upwards {
10230                    Point::new(rows.end.0, 0)
10231                } else {
10232                    start
10233                };
10234                edits.push((insert_location..insert_location, text));
10235            } else {
10236                // duplicate character-wise
10237                let start = selection.start;
10238                let end = selection.end;
10239                let text = buffer.text_for_range(start..end).collect::<String>();
10240                edits.push((selection.end..selection.end, text));
10241            }
10242        }
10243
10244        self.transact(window, cx, |this, _, cx| {
10245            this.buffer.update(cx, |buffer, cx| {
10246                buffer.edit(edits, None, cx);
10247            });
10248
10249            this.request_autoscroll(Autoscroll::fit(), cx);
10250        });
10251    }
10252
10253    pub fn duplicate_line_up(
10254        &mut self,
10255        _: &DuplicateLineUp,
10256        window: &mut Window,
10257        cx: &mut Context<Self>,
10258    ) {
10259        self.duplicate(true, true, window, cx);
10260    }
10261
10262    pub fn duplicate_line_down(
10263        &mut self,
10264        _: &DuplicateLineDown,
10265        window: &mut Window,
10266        cx: &mut Context<Self>,
10267    ) {
10268        self.duplicate(false, true, window, cx);
10269    }
10270
10271    pub fn duplicate_selection(
10272        &mut self,
10273        _: &DuplicateSelection,
10274        window: &mut Window,
10275        cx: &mut Context<Self>,
10276    ) {
10277        self.duplicate(false, false, window, cx);
10278    }
10279
10280    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10281        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10282
10283        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10284        let buffer = self.buffer.read(cx).snapshot(cx);
10285
10286        let mut edits = Vec::new();
10287        let mut unfold_ranges = Vec::new();
10288        let mut refold_creases = Vec::new();
10289
10290        let selections = self.selections.all::<Point>(cx);
10291        let mut selections = selections.iter().peekable();
10292        let mut contiguous_row_selections = Vec::new();
10293        let mut new_selections = Vec::new();
10294
10295        while let Some(selection) = selections.next() {
10296            // Find all the selections that span a contiguous row range
10297            let (start_row, end_row) = consume_contiguous_rows(
10298                &mut contiguous_row_selections,
10299                selection,
10300                &display_map,
10301                &mut selections,
10302            );
10303
10304            // Move the text spanned by the row range to be before the line preceding the row range
10305            if start_row.0 > 0 {
10306                let range_to_move = Point::new(
10307                    start_row.previous_row().0,
10308                    buffer.line_len(start_row.previous_row()),
10309                )
10310                    ..Point::new(
10311                        end_row.previous_row().0,
10312                        buffer.line_len(end_row.previous_row()),
10313                    );
10314                let insertion_point = display_map
10315                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10316                    .0;
10317
10318                // Don't move lines across excerpts
10319                if buffer
10320                    .excerpt_containing(insertion_point..range_to_move.end)
10321                    .is_some()
10322                {
10323                    let text = buffer
10324                        .text_for_range(range_to_move.clone())
10325                        .flat_map(|s| s.chars())
10326                        .skip(1)
10327                        .chain(['\n'])
10328                        .collect::<String>();
10329
10330                    edits.push((
10331                        buffer.anchor_after(range_to_move.start)
10332                            ..buffer.anchor_before(range_to_move.end),
10333                        String::new(),
10334                    ));
10335                    let insertion_anchor = buffer.anchor_after(insertion_point);
10336                    edits.push((insertion_anchor..insertion_anchor, text));
10337
10338                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10339
10340                    // Move selections up
10341                    new_selections.extend(contiguous_row_selections.drain(..).map(
10342                        |mut selection| {
10343                            selection.start.row -= row_delta;
10344                            selection.end.row -= row_delta;
10345                            selection
10346                        },
10347                    ));
10348
10349                    // Move folds up
10350                    unfold_ranges.push(range_to_move.clone());
10351                    for fold in display_map.folds_in_range(
10352                        buffer.anchor_before(range_to_move.start)
10353                            ..buffer.anchor_after(range_to_move.end),
10354                    ) {
10355                        let mut start = fold.range.start.to_point(&buffer);
10356                        let mut end = fold.range.end.to_point(&buffer);
10357                        start.row -= row_delta;
10358                        end.row -= row_delta;
10359                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10360                    }
10361                }
10362            }
10363
10364            // If we didn't move line(s), preserve the existing selections
10365            new_selections.append(&mut contiguous_row_selections);
10366        }
10367
10368        self.transact(window, cx, |this, window, cx| {
10369            this.unfold_ranges(&unfold_ranges, true, true, cx);
10370            this.buffer.update(cx, |buffer, cx| {
10371                for (range, text) in edits {
10372                    buffer.edit([(range, text)], None, cx);
10373                }
10374            });
10375            this.fold_creases(refold_creases, true, window, cx);
10376            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10377                s.select(new_selections);
10378            })
10379        });
10380    }
10381
10382    pub fn move_line_down(
10383        &mut self,
10384        _: &MoveLineDown,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10389
10390        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10391        let buffer = self.buffer.read(cx).snapshot(cx);
10392
10393        let mut edits = Vec::new();
10394        let mut unfold_ranges = Vec::new();
10395        let mut refold_creases = Vec::new();
10396
10397        let selections = self.selections.all::<Point>(cx);
10398        let mut selections = selections.iter().peekable();
10399        let mut contiguous_row_selections = Vec::new();
10400        let mut new_selections = Vec::new();
10401
10402        while let Some(selection) = selections.next() {
10403            // Find all the selections that span a contiguous row range
10404            let (start_row, end_row) = consume_contiguous_rows(
10405                &mut contiguous_row_selections,
10406                selection,
10407                &display_map,
10408                &mut selections,
10409            );
10410
10411            // Move the text spanned by the row range to be after the last line of the row range
10412            if end_row.0 <= buffer.max_point().row {
10413                let range_to_move =
10414                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10415                let insertion_point = display_map
10416                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10417                    .0;
10418
10419                // Don't move lines across excerpt boundaries
10420                if buffer
10421                    .excerpt_containing(range_to_move.start..insertion_point)
10422                    .is_some()
10423                {
10424                    let mut text = String::from("\n");
10425                    text.extend(buffer.text_for_range(range_to_move.clone()));
10426                    text.pop(); // Drop trailing newline
10427                    edits.push((
10428                        buffer.anchor_after(range_to_move.start)
10429                            ..buffer.anchor_before(range_to_move.end),
10430                        String::new(),
10431                    ));
10432                    let insertion_anchor = buffer.anchor_after(insertion_point);
10433                    edits.push((insertion_anchor..insertion_anchor, text));
10434
10435                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10436
10437                    // Move selections down
10438                    new_selections.extend(contiguous_row_selections.drain(..).map(
10439                        |mut selection| {
10440                            selection.start.row += row_delta;
10441                            selection.end.row += row_delta;
10442                            selection
10443                        },
10444                    ));
10445
10446                    // Move folds down
10447                    unfold_ranges.push(range_to_move.clone());
10448                    for fold in display_map.folds_in_range(
10449                        buffer.anchor_before(range_to_move.start)
10450                            ..buffer.anchor_after(range_to_move.end),
10451                    ) {
10452                        let mut start = fold.range.start.to_point(&buffer);
10453                        let mut end = fold.range.end.to_point(&buffer);
10454                        start.row += row_delta;
10455                        end.row += row_delta;
10456                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10457                    }
10458                }
10459            }
10460
10461            // If we didn't move line(s), preserve the existing selections
10462            new_selections.append(&mut contiguous_row_selections);
10463        }
10464
10465        self.transact(window, cx, |this, window, cx| {
10466            this.unfold_ranges(&unfold_ranges, true, true, cx);
10467            this.buffer.update(cx, |buffer, cx| {
10468                for (range, text) in edits {
10469                    buffer.edit([(range, text)], None, cx);
10470                }
10471            });
10472            this.fold_creases(refold_creases, true, window, cx);
10473            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10474                s.select(new_selections)
10475            });
10476        });
10477    }
10478
10479    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10480        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10481        let text_layout_details = &self.text_layout_details(window);
10482        self.transact(window, cx, |this, window, cx| {
10483            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10484                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10485                s.move_with(|display_map, selection| {
10486                    if !selection.is_empty() {
10487                        return;
10488                    }
10489
10490                    let mut head = selection.head();
10491                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10492                    if head.column() == display_map.line_len(head.row()) {
10493                        transpose_offset = display_map
10494                            .buffer_snapshot
10495                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10496                    }
10497
10498                    if transpose_offset == 0 {
10499                        return;
10500                    }
10501
10502                    *head.column_mut() += 1;
10503                    head = display_map.clip_point(head, Bias::Right);
10504                    let goal = SelectionGoal::HorizontalPosition(
10505                        display_map
10506                            .x_for_display_point(head, text_layout_details)
10507                            .into(),
10508                    );
10509                    selection.collapse_to(head, goal);
10510
10511                    let transpose_start = display_map
10512                        .buffer_snapshot
10513                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10514                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10515                        let transpose_end = display_map
10516                            .buffer_snapshot
10517                            .clip_offset(transpose_offset + 1, Bias::Right);
10518                        if let Some(ch) =
10519                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10520                        {
10521                            edits.push((transpose_start..transpose_offset, String::new()));
10522                            edits.push((transpose_end..transpose_end, ch.to_string()));
10523                        }
10524                    }
10525                });
10526                edits
10527            });
10528            this.buffer
10529                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10530            let selections = this.selections.all::<usize>(cx);
10531            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10532                s.select(selections);
10533            });
10534        });
10535    }
10536
10537    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10538        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10539        self.rewrap_impl(RewrapOptions::default(), cx)
10540    }
10541
10542    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10543        let buffer = self.buffer.read(cx).snapshot(cx);
10544        let selections = self.selections.all::<Point>(cx);
10545        let mut selections = selections.iter().peekable();
10546
10547        let mut edits = Vec::new();
10548        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10549
10550        while let Some(selection) = selections.next() {
10551            let mut start_row = selection.start.row;
10552            let mut end_row = selection.end.row;
10553
10554            // Skip selections that overlap with a range that has already been rewrapped.
10555            let selection_range = start_row..end_row;
10556            if rewrapped_row_ranges
10557                .iter()
10558                .any(|range| range.overlaps(&selection_range))
10559            {
10560                continue;
10561            }
10562
10563            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10564
10565            // Since not all lines in the selection may be at the same indent
10566            // level, choose the indent size that is the most common between all
10567            // of the lines.
10568            //
10569            // If there is a tie, we use the deepest indent.
10570            let (indent_size, indent_end) = {
10571                let mut indent_size_occurrences = HashMap::default();
10572                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10573
10574                for row in start_row..=end_row {
10575                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10576                    rows_by_indent_size.entry(indent).or_default().push(row);
10577                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10578                }
10579
10580                let indent_size = indent_size_occurrences
10581                    .into_iter()
10582                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10583                    .map(|(indent, _)| indent)
10584                    .unwrap_or_default();
10585                let row = rows_by_indent_size[&indent_size][0];
10586                let indent_end = Point::new(row, indent_size.len);
10587
10588                (indent_size, indent_end)
10589            };
10590
10591            let mut line_prefix = indent_size.chars().collect::<String>();
10592
10593            let mut inside_comment = false;
10594            if let Some(comment_prefix) =
10595                buffer
10596                    .language_scope_at(selection.head())
10597                    .and_then(|language| {
10598                        language
10599                            .line_comment_prefixes()
10600                            .iter()
10601                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10602                            .cloned()
10603                    })
10604            {
10605                line_prefix.push_str(&comment_prefix);
10606                inside_comment = true;
10607            }
10608
10609            let language_settings = buffer.language_settings_at(selection.head(), cx);
10610            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10611                RewrapBehavior::InComments => inside_comment,
10612                RewrapBehavior::InSelections => !selection.is_empty(),
10613                RewrapBehavior::Anywhere => true,
10614            };
10615
10616            let should_rewrap = options.override_language_settings
10617                || allow_rewrap_based_on_language
10618                || self.hard_wrap.is_some();
10619            if !should_rewrap {
10620                continue;
10621            }
10622
10623            if selection.is_empty() {
10624                'expand_upwards: while start_row > 0 {
10625                    let prev_row = start_row - 1;
10626                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10627                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10628                    {
10629                        start_row = prev_row;
10630                    } else {
10631                        break 'expand_upwards;
10632                    }
10633                }
10634
10635                'expand_downwards: while end_row < buffer.max_point().row {
10636                    let next_row = end_row + 1;
10637                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10638                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10639                    {
10640                        end_row = next_row;
10641                    } else {
10642                        break 'expand_downwards;
10643                    }
10644                }
10645            }
10646
10647            let start = Point::new(start_row, 0);
10648            let start_offset = start.to_offset(&buffer);
10649            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10650            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10651            let Some(lines_without_prefixes) = selection_text
10652                .lines()
10653                .map(|line| {
10654                    line.strip_prefix(&line_prefix)
10655                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10656                        .with_context(|| {
10657                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10658                        })
10659                })
10660                .collect::<Result<Vec<_>, _>>()
10661                .log_err()
10662            else {
10663                continue;
10664            };
10665
10666            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10667                buffer
10668                    .language_settings_at(Point::new(start_row, 0), cx)
10669                    .preferred_line_length as usize
10670            });
10671            let wrapped_text = wrap_with_prefix(
10672                line_prefix,
10673                lines_without_prefixes.join("\n"),
10674                wrap_column,
10675                tab_size,
10676                options.preserve_existing_whitespace,
10677            );
10678
10679            // TODO: should always use char-based diff while still supporting cursor behavior that
10680            // matches vim.
10681            let mut diff_options = DiffOptions::default();
10682            if options.override_language_settings {
10683                diff_options.max_word_diff_len = 0;
10684                diff_options.max_word_diff_line_count = 0;
10685            } else {
10686                diff_options.max_word_diff_len = usize::MAX;
10687                diff_options.max_word_diff_line_count = usize::MAX;
10688            }
10689
10690            for (old_range, new_text) in
10691                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10692            {
10693                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10694                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10695                edits.push((edit_start..edit_end, new_text));
10696            }
10697
10698            rewrapped_row_ranges.push(start_row..=end_row);
10699        }
10700
10701        self.buffer
10702            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10703    }
10704
10705    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10706        let mut text = String::new();
10707        let buffer = self.buffer.read(cx).snapshot(cx);
10708        let mut selections = self.selections.all::<Point>(cx);
10709        let mut clipboard_selections = Vec::with_capacity(selections.len());
10710        {
10711            let max_point = buffer.max_point();
10712            let mut is_first = true;
10713            for selection in &mut selections {
10714                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10715                if is_entire_line {
10716                    selection.start = Point::new(selection.start.row, 0);
10717                    if !selection.is_empty() && selection.end.column == 0 {
10718                        selection.end = cmp::min(max_point, selection.end);
10719                    } else {
10720                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10721                    }
10722                    selection.goal = SelectionGoal::None;
10723                }
10724                if is_first {
10725                    is_first = false;
10726                } else {
10727                    text += "\n";
10728                }
10729                let mut len = 0;
10730                for chunk in buffer.text_for_range(selection.start..selection.end) {
10731                    text.push_str(chunk);
10732                    len += chunk.len();
10733                }
10734                clipboard_selections.push(ClipboardSelection {
10735                    len,
10736                    is_entire_line,
10737                    first_line_indent: buffer
10738                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10739                        .len,
10740                });
10741            }
10742        }
10743
10744        self.transact(window, cx, |this, window, cx| {
10745            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10746                s.select(selections);
10747            });
10748            this.insert("", window, cx);
10749        });
10750        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10751    }
10752
10753    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10754        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10755        let item = self.cut_common(window, cx);
10756        cx.write_to_clipboard(item);
10757    }
10758
10759    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10760        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10761        self.change_selections(None, window, cx, |s| {
10762            s.move_with(|snapshot, sel| {
10763                if sel.is_empty() {
10764                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10765                }
10766            });
10767        });
10768        let item = self.cut_common(window, cx);
10769        cx.set_global(KillRing(item))
10770    }
10771
10772    pub fn kill_ring_yank(
10773        &mut self,
10774        _: &KillRingYank,
10775        window: &mut Window,
10776        cx: &mut Context<Self>,
10777    ) {
10778        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10779        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10780            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10781                (kill_ring.text().to_string(), kill_ring.metadata_json())
10782            } else {
10783                return;
10784            }
10785        } else {
10786            return;
10787        };
10788        self.do_paste(&text, metadata, false, window, cx);
10789    }
10790
10791    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10792        self.do_copy(true, cx);
10793    }
10794
10795    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10796        self.do_copy(false, cx);
10797    }
10798
10799    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10800        let selections = self.selections.all::<Point>(cx);
10801        let buffer = self.buffer.read(cx).read(cx);
10802        let mut text = String::new();
10803
10804        let mut clipboard_selections = Vec::with_capacity(selections.len());
10805        {
10806            let max_point = buffer.max_point();
10807            let mut is_first = true;
10808            for selection in &selections {
10809                let mut start = selection.start;
10810                let mut end = selection.end;
10811                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10812                if is_entire_line {
10813                    start = Point::new(start.row, 0);
10814                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10815                }
10816
10817                let mut trimmed_selections = Vec::new();
10818                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10819                    let row = MultiBufferRow(start.row);
10820                    let first_indent = buffer.indent_size_for_line(row);
10821                    if first_indent.len == 0 || start.column > first_indent.len {
10822                        trimmed_selections.push(start..end);
10823                    } else {
10824                        trimmed_selections.push(
10825                            Point::new(row.0, first_indent.len)
10826                                ..Point::new(row.0, buffer.line_len(row)),
10827                        );
10828                        for row in start.row + 1..=end.row {
10829                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10830                            if row == end.row {
10831                                line_len = end.column;
10832                            }
10833                            if line_len == 0 {
10834                                trimmed_selections
10835                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10836                                continue;
10837                            }
10838                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
10839                            if row_indent_size.len >= first_indent.len {
10840                                trimmed_selections.push(
10841                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
10842                                );
10843                            } else {
10844                                trimmed_selections.clear();
10845                                trimmed_selections.push(start..end);
10846                                break;
10847                            }
10848                        }
10849                    }
10850                } else {
10851                    trimmed_selections.push(start..end);
10852                }
10853
10854                for trimmed_range in trimmed_selections {
10855                    if is_first {
10856                        is_first = false;
10857                    } else {
10858                        text += "\n";
10859                    }
10860                    let mut len = 0;
10861                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
10862                        text.push_str(chunk);
10863                        len += chunk.len();
10864                    }
10865                    clipboard_selections.push(ClipboardSelection {
10866                        len,
10867                        is_entire_line,
10868                        first_line_indent: buffer
10869                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
10870                            .len,
10871                    });
10872                }
10873            }
10874        }
10875
10876        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
10877            text,
10878            clipboard_selections,
10879        ));
10880    }
10881
10882    pub fn do_paste(
10883        &mut self,
10884        text: &String,
10885        clipboard_selections: Option<Vec<ClipboardSelection>>,
10886        handle_entire_lines: bool,
10887        window: &mut Window,
10888        cx: &mut Context<Self>,
10889    ) {
10890        if self.read_only(cx) {
10891            return;
10892        }
10893
10894        let clipboard_text = Cow::Borrowed(text);
10895
10896        self.transact(window, cx, |this, window, cx| {
10897            if let Some(mut clipboard_selections) = clipboard_selections {
10898                let old_selections = this.selections.all::<usize>(cx);
10899                let all_selections_were_entire_line =
10900                    clipboard_selections.iter().all(|s| s.is_entire_line);
10901                let first_selection_indent_column =
10902                    clipboard_selections.first().map(|s| s.first_line_indent);
10903                if clipboard_selections.len() != old_selections.len() {
10904                    clipboard_selections.drain(..);
10905                }
10906                let cursor_offset = this.selections.last::<usize>(cx).head();
10907                let mut auto_indent_on_paste = true;
10908
10909                this.buffer.update(cx, |buffer, cx| {
10910                    let snapshot = buffer.read(cx);
10911                    auto_indent_on_paste = snapshot
10912                        .language_settings_at(cursor_offset, cx)
10913                        .auto_indent_on_paste;
10914
10915                    let mut start_offset = 0;
10916                    let mut edits = Vec::new();
10917                    let mut original_indent_columns = Vec::new();
10918                    for (ix, selection) in old_selections.iter().enumerate() {
10919                        let to_insert;
10920                        let entire_line;
10921                        let original_indent_column;
10922                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
10923                            let end_offset = start_offset + clipboard_selection.len;
10924                            to_insert = &clipboard_text[start_offset..end_offset];
10925                            entire_line = clipboard_selection.is_entire_line;
10926                            start_offset = end_offset + 1;
10927                            original_indent_column = Some(clipboard_selection.first_line_indent);
10928                        } else {
10929                            to_insert = clipboard_text.as_str();
10930                            entire_line = all_selections_were_entire_line;
10931                            original_indent_column = first_selection_indent_column
10932                        }
10933
10934                        // If the corresponding selection was empty when this slice of the
10935                        // clipboard text was written, then the entire line containing the
10936                        // selection was copied. If this selection is also currently empty,
10937                        // then paste the line before the current line of the buffer.
10938                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
10939                            let column = selection.start.to_point(&snapshot).column as usize;
10940                            let line_start = selection.start - column;
10941                            line_start..line_start
10942                        } else {
10943                            selection.range()
10944                        };
10945
10946                        edits.push((range, to_insert));
10947                        original_indent_columns.push(original_indent_column);
10948                    }
10949                    drop(snapshot);
10950
10951                    buffer.edit(
10952                        edits,
10953                        if auto_indent_on_paste {
10954                            Some(AutoindentMode::Block {
10955                                original_indent_columns,
10956                            })
10957                        } else {
10958                            None
10959                        },
10960                        cx,
10961                    );
10962                });
10963
10964                let selections = this.selections.all::<usize>(cx);
10965                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10966                    s.select(selections)
10967                });
10968            } else {
10969                this.insert(&clipboard_text, window, cx);
10970            }
10971        });
10972    }
10973
10974    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
10975        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10976        if let Some(item) = cx.read_from_clipboard() {
10977            let entries = item.entries();
10978
10979            match entries.first() {
10980                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
10981                // of all the pasted entries.
10982                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
10983                    .do_paste(
10984                        clipboard_string.text(),
10985                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
10986                        true,
10987                        window,
10988                        cx,
10989                    ),
10990                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
10991            }
10992        }
10993    }
10994
10995    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
10996        if self.read_only(cx) {
10997            return;
10998        }
10999
11000        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11001
11002        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11003            if let Some((selections, _)) =
11004                self.selection_history.transaction(transaction_id).cloned()
11005            {
11006                self.change_selections(None, window, cx, |s| {
11007                    s.select_anchors(selections.to_vec());
11008                });
11009            } else {
11010                log::error!(
11011                    "No entry in selection_history found for undo. \
11012                     This may correspond to a bug where undo does not update the selection. \
11013                     If this is occurring, please add details to \
11014                     https://github.com/zed-industries/zed/issues/22692"
11015                );
11016            }
11017            self.request_autoscroll(Autoscroll::fit(), cx);
11018            self.unmark_text(window, cx);
11019            self.refresh_inline_completion(true, false, window, cx);
11020            cx.emit(EditorEvent::Edited { transaction_id });
11021            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11022        }
11023    }
11024
11025    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11026        if self.read_only(cx) {
11027            return;
11028        }
11029
11030        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11031
11032        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11033            if let Some((_, Some(selections))) =
11034                self.selection_history.transaction(transaction_id).cloned()
11035            {
11036                self.change_selections(None, window, cx, |s| {
11037                    s.select_anchors(selections.to_vec());
11038                });
11039            } else {
11040                log::error!(
11041                    "No entry in selection_history found for redo. \
11042                     This may correspond to a bug where undo does not update the selection. \
11043                     If this is occurring, please add details to \
11044                     https://github.com/zed-industries/zed/issues/22692"
11045                );
11046            }
11047            self.request_autoscroll(Autoscroll::fit(), cx);
11048            self.unmark_text(window, cx);
11049            self.refresh_inline_completion(true, false, window, cx);
11050            cx.emit(EditorEvent::Edited { transaction_id });
11051        }
11052    }
11053
11054    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11055        self.buffer
11056            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11057    }
11058
11059    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11060        self.buffer
11061            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11062    }
11063
11064    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11065        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11066        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11067            s.move_with(|map, selection| {
11068                let cursor = if selection.is_empty() {
11069                    movement::left(map, selection.start)
11070                } else {
11071                    selection.start
11072                };
11073                selection.collapse_to(cursor, SelectionGoal::None);
11074            });
11075        })
11076    }
11077
11078    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11079        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11080        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11081            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11082        })
11083    }
11084
11085    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11086        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11087        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11088            s.move_with(|map, selection| {
11089                let cursor = if selection.is_empty() {
11090                    movement::right(map, selection.end)
11091                } else {
11092                    selection.end
11093                };
11094                selection.collapse_to(cursor, SelectionGoal::None)
11095            });
11096        })
11097    }
11098
11099    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11100        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11101        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11102            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11103        })
11104    }
11105
11106    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11107        if self.take_rename(true, window, cx).is_some() {
11108            return;
11109        }
11110
11111        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11112            cx.propagate();
11113            return;
11114        }
11115
11116        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11117
11118        let text_layout_details = &self.text_layout_details(window);
11119        let selection_count = self.selections.count();
11120        let first_selection = self.selections.first_anchor();
11121
11122        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11123            s.move_with(|map, selection| {
11124                if !selection.is_empty() {
11125                    selection.goal = SelectionGoal::None;
11126                }
11127                let (cursor, goal) = movement::up(
11128                    map,
11129                    selection.start,
11130                    selection.goal,
11131                    false,
11132                    text_layout_details,
11133                );
11134                selection.collapse_to(cursor, goal);
11135            });
11136        });
11137
11138        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11139        {
11140            cx.propagate();
11141        }
11142    }
11143
11144    pub fn move_up_by_lines(
11145        &mut self,
11146        action: &MoveUpByLines,
11147        window: &mut Window,
11148        cx: &mut Context<Self>,
11149    ) {
11150        if self.take_rename(true, window, cx).is_some() {
11151            return;
11152        }
11153
11154        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11155            cx.propagate();
11156            return;
11157        }
11158
11159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11160
11161        let text_layout_details = &self.text_layout_details(window);
11162
11163        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11164            s.move_with(|map, selection| {
11165                if !selection.is_empty() {
11166                    selection.goal = SelectionGoal::None;
11167                }
11168                let (cursor, goal) = movement::up_by_rows(
11169                    map,
11170                    selection.start,
11171                    action.lines,
11172                    selection.goal,
11173                    false,
11174                    text_layout_details,
11175                );
11176                selection.collapse_to(cursor, goal);
11177            });
11178        })
11179    }
11180
11181    pub fn move_down_by_lines(
11182        &mut self,
11183        action: &MoveDownByLines,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        if self.take_rename(true, window, cx).is_some() {
11188            return;
11189        }
11190
11191        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11192            cx.propagate();
11193            return;
11194        }
11195
11196        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11197
11198        let text_layout_details = &self.text_layout_details(window);
11199
11200        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11201            s.move_with(|map, selection| {
11202                if !selection.is_empty() {
11203                    selection.goal = SelectionGoal::None;
11204                }
11205                let (cursor, goal) = movement::down_by_rows(
11206                    map,
11207                    selection.start,
11208                    action.lines,
11209                    selection.goal,
11210                    false,
11211                    text_layout_details,
11212                );
11213                selection.collapse_to(cursor, goal);
11214            });
11215        })
11216    }
11217
11218    pub fn select_down_by_lines(
11219        &mut self,
11220        action: &SelectDownByLines,
11221        window: &mut Window,
11222        cx: &mut Context<Self>,
11223    ) {
11224        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11225        let text_layout_details = &self.text_layout_details(window);
11226        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11227            s.move_heads_with(|map, head, goal| {
11228                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11229            })
11230        })
11231    }
11232
11233    pub fn select_up_by_lines(
11234        &mut self,
11235        action: &SelectUpByLines,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11240        let text_layout_details = &self.text_layout_details(window);
11241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11242            s.move_heads_with(|map, head, goal| {
11243                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11244            })
11245        })
11246    }
11247
11248    pub fn select_page_up(
11249        &mut self,
11250        _: &SelectPageUp,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        let Some(row_count) = self.visible_row_count() else {
11255            return;
11256        };
11257
11258        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11259
11260        let text_layout_details = &self.text_layout_details(window);
11261
11262        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11263            s.move_heads_with(|map, head, goal| {
11264                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11265            })
11266        })
11267    }
11268
11269    pub fn move_page_up(
11270        &mut self,
11271        action: &MovePageUp,
11272        window: &mut Window,
11273        cx: &mut Context<Self>,
11274    ) {
11275        if self.take_rename(true, window, cx).is_some() {
11276            return;
11277        }
11278
11279        if self
11280            .context_menu
11281            .borrow_mut()
11282            .as_mut()
11283            .map(|menu| menu.select_first(self.completion_provider.as_deref(), cx))
11284            .unwrap_or(false)
11285        {
11286            return;
11287        }
11288
11289        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11290            cx.propagate();
11291            return;
11292        }
11293
11294        let Some(row_count) = self.visible_row_count() else {
11295            return;
11296        };
11297
11298        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11299
11300        let autoscroll = if action.center_cursor {
11301            Autoscroll::center()
11302        } else {
11303            Autoscroll::fit()
11304        };
11305
11306        let text_layout_details = &self.text_layout_details(window);
11307
11308        self.change_selections(Some(autoscroll), window, cx, |s| {
11309            s.move_with(|map, selection| {
11310                if !selection.is_empty() {
11311                    selection.goal = SelectionGoal::None;
11312                }
11313                let (cursor, goal) = movement::up_by_rows(
11314                    map,
11315                    selection.end,
11316                    row_count,
11317                    selection.goal,
11318                    false,
11319                    text_layout_details,
11320                );
11321                selection.collapse_to(cursor, goal);
11322            });
11323        });
11324    }
11325
11326    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11327        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11328        let text_layout_details = &self.text_layout_details(window);
11329        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11330            s.move_heads_with(|map, head, goal| {
11331                movement::up(map, head, goal, false, text_layout_details)
11332            })
11333        })
11334    }
11335
11336    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11337        self.take_rename(true, window, cx);
11338
11339        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11340            cx.propagate();
11341            return;
11342        }
11343
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11345
11346        let text_layout_details = &self.text_layout_details(window);
11347        let selection_count = self.selections.count();
11348        let first_selection = self.selections.first_anchor();
11349
11350        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11351            s.move_with(|map, selection| {
11352                if !selection.is_empty() {
11353                    selection.goal = SelectionGoal::None;
11354                }
11355                let (cursor, goal) = movement::down(
11356                    map,
11357                    selection.end,
11358                    selection.goal,
11359                    false,
11360                    text_layout_details,
11361                );
11362                selection.collapse_to(cursor, goal);
11363            });
11364        });
11365
11366        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11367        {
11368            cx.propagate();
11369        }
11370    }
11371
11372    pub fn select_page_down(
11373        &mut self,
11374        _: &SelectPageDown,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        let Some(row_count) = self.visible_row_count() else {
11379            return;
11380        };
11381
11382        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11383
11384        let text_layout_details = &self.text_layout_details(window);
11385
11386        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11387            s.move_heads_with(|map, head, goal| {
11388                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11389            })
11390        })
11391    }
11392
11393    pub fn move_page_down(
11394        &mut self,
11395        action: &MovePageDown,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        if self.take_rename(true, window, cx).is_some() {
11400            return;
11401        }
11402
11403        if self
11404            .context_menu
11405            .borrow_mut()
11406            .as_mut()
11407            .map(|menu| menu.select_last(self.completion_provider.as_deref(), cx))
11408            .unwrap_or(false)
11409        {
11410            return;
11411        }
11412
11413        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11414            cx.propagate();
11415            return;
11416        }
11417
11418        let Some(row_count) = self.visible_row_count() else {
11419            return;
11420        };
11421
11422        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11423
11424        let autoscroll = if action.center_cursor {
11425            Autoscroll::center()
11426        } else {
11427            Autoscroll::fit()
11428        };
11429
11430        let text_layout_details = &self.text_layout_details(window);
11431        self.change_selections(Some(autoscroll), window, cx, |s| {
11432            s.move_with(|map, selection| {
11433                if !selection.is_empty() {
11434                    selection.goal = SelectionGoal::None;
11435                }
11436                let (cursor, goal) = movement::down_by_rows(
11437                    map,
11438                    selection.end,
11439                    row_count,
11440                    selection.goal,
11441                    false,
11442                    text_layout_details,
11443                );
11444                selection.collapse_to(cursor, goal);
11445            });
11446        });
11447    }
11448
11449    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11450        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11451        let text_layout_details = &self.text_layout_details(window);
11452        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11453            s.move_heads_with(|map, head, goal| {
11454                movement::down(map, head, goal, false, text_layout_details)
11455            })
11456        });
11457    }
11458
11459    pub fn context_menu_first(
11460        &mut self,
11461        _: &ContextMenuFirst,
11462        _window: &mut Window,
11463        cx: &mut Context<Self>,
11464    ) {
11465        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11466            context_menu.select_first(self.completion_provider.as_deref(), cx);
11467        }
11468    }
11469
11470    pub fn context_menu_prev(
11471        &mut self,
11472        _: &ContextMenuPrevious,
11473        _window: &mut Window,
11474        cx: &mut Context<Self>,
11475    ) {
11476        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11477            context_menu.select_prev(self.completion_provider.as_deref(), cx);
11478        }
11479    }
11480
11481    pub fn context_menu_next(
11482        &mut self,
11483        _: &ContextMenuNext,
11484        _window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11488            context_menu.select_next(self.completion_provider.as_deref(), cx);
11489        }
11490    }
11491
11492    pub fn context_menu_last(
11493        &mut self,
11494        _: &ContextMenuLast,
11495        _window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11499            context_menu.select_last(self.completion_provider.as_deref(), cx);
11500        }
11501    }
11502
11503    pub fn move_to_previous_word_start(
11504        &mut self,
11505        _: &MoveToPreviousWordStart,
11506        window: &mut Window,
11507        cx: &mut Context<Self>,
11508    ) {
11509        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11510        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11511            s.move_cursors_with(|map, head, _| {
11512                (
11513                    movement::previous_word_start(map, head),
11514                    SelectionGoal::None,
11515                )
11516            });
11517        })
11518    }
11519
11520    pub fn move_to_previous_subword_start(
11521        &mut self,
11522        _: &MoveToPreviousSubwordStart,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11527        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11528            s.move_cursors_with(|map, head, _| {
11529                (
11530                    movement::previous_subword_start(map, head),
11531                    SelectionGoal::None,
11532                )
11533            });
11534        })
11535    }
11536
11537    pub fn select_to_previous_word_start(
11538        &mut self,
11539        _: &SelectToPreviousWordStart,
11540        window: &mut Window,
11541        cx: &mut Context<Self>,
11542    ) {
11543        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11544        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11545            s.move_heads_with(|map, head, _| {
11546                (
11547                    movement::previous_word_start(map, head),
11548                    SelectionGoal::None,
11549                )
11550            });
11551        })
11552    }
11553
11554    pub fn select_to_previous_subword_start(
11555        &mut self,
11556        _: &SelectToPreviousSubwordStart,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11561        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11562            s.move_heads_with(|map, head, _| {
11563                (
11564                    movement::previous_subword_start(map, head),
11565                    SelectionGoal::None,
11566                )
11567            });
11568        })
11569    }
11570
11571    pub fn delete_to_previous_word_start(
11572        &mut self,
11573        action: &DeleteToPreviousWordStart,
11574        window: &mut Window,
11575        cx: &mut Context<Self>,
11576    ) {
11577        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11578        self.transact(window, cx, |this, window, cx| {
11579            this.select_autoclose_pair(window, cx);
11580            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11581                s.move_with(|map, selection| {
11582                    if selection.is_empty() {
11583                        let cursor = if action.ignore_newlines {
11584                            movement::previous_word_start(map, selection.head())
11585                        } else {
11586                            movement::previous_word_start_or_newline(map, selection.head())
11587                        };
11588                        selection.set_head(cursor, SelectionGoal::None);
11589                    }
11590                });
11591            });
11592            this.insert("", window, cx);
11593        });
11594    }
11595
11596    pub fn delete_to_previous_subword_start(
11597        &mut self,
11598        _: &DeleteToPreviousSubwordStart,
11599        window: &mut Window,
11600        cx: &mut Context<Self>,
11601    ) {
11602        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11603        self.transact(window, cx, |this, window, cx| {
11604            this.select_autoclose_pair(window, cx);
11605            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11606                s.move_with(|map, selection| {
11607                    if selection.is_empty() {
11608                        let cursor = movement::previous_subword_start(map, selection.head());
11609                        selection.set_head(cursor, SelectionGoal::None);
11610                    }
11611                });
11612            });
11613            this.insert("", window, cx);
11614        });
11615    }
11616
11617    pub fn move_to_next_word_end(
11618        &mut self,
11619        _: &MoveToNextWordEnd,
11620        window: &mut Window,
11621        cx: &mut Context<Self>,
11622    ) {
11623        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11624        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11625            s.move_cursors_with(|map, head, _| {
11626                (movement::next_word_end(map, head), SelectionGoal::None)
11627            });
11628        })
11629    }
11630
11631    pub fn move_to_next_subword_end(
11632        &mut self,
11633        _: &MoveToNextSubwordEnd,
11634        window: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11638        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11639            s.move_cursors_with(|map, head, _| {
11640                (movement::next_subword_end(map, head), SelectionGoal::None)
11641            });
11642        })
11643    }
11644
11645    pub fn select_to_next_word_end(
11646        &mut self,
11647        _: &SelectToNextWordEnd,
11648        window: &mut Window,
11649        cx: &mut Context<Self>,
11650    ) {
11651        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11652        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11653            s.move_heads_with(|map, head, _| {
11654                (movement::next_word_end(map, head), SelectionGoal::None)
11655            });
11656        })
11657    }
11658
11659    pub fn select_to_next_subword_end(
11660        &mut self,
11661        _: &SelectToNextSubwordEnd,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11666        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11667            s.move_heads_with(|map, head, _| {
11668                (movement::next_subword_end(map, head), SelectionGoal::None)
11669            });
11670        })
11671    }
11672
11673    pub fn delete_to_next_word_end(
11674        &mut self,
11675        action: &DeleteToNextWordEnd,
11676        window: &mut Window,
11677        cx: &mut Context<Self>,
11678    ) {
11679        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11680        self.transact(window, cx, |this, window, cx| {
11681            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11682                s.move_with(|map, selection| {
11683                    if selection.is_empty() {
11684                        let cursor = if action.ignore_newlines {
11685                            movement::next_word_end(map, selection.head())
11686                        } else {
11687                            movement::next_word_end_or_newline(map, selection.head())
11688                        };
11689                        selection.set_head(cursor, SelectionGoal::None);
11690                    }
11691                });
11692            });
11693            this.insert("", window, cx);
11694        });
11695    }
11696
11697    pub fn delete_to_next_subword_end(
11698        &mut self,
11699        _: &DeleteToNextSubwordEnd,
11700        window: &mut Window,
11701        cx: &mut Context<Self>,
11702    ) {
11703        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11704        self.transact(window, cx, |this, window, cx| {
11705            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11706                s.move_with(|map, selection| {
11707                    if selection.is_empty() {
11708                        let cursor = movement::next_subword_end(map, selection.head());
11709                        selection.set_head(cursor, SelectionGoal::None);
11710                    }
11711                });
11712            });
11713            this.insert("", window, cx);
11714        });
11715    }
11716
11717    pub fn move_to_beginning_of_line(
11718        &mut self,
11719        action: &MoveToBeginningOfLine,
11720        window: &mut Window,
11721        cx: &mut Context<Self>,
11722    ) {
11723        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11724        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11725            s.move_cursors_with(|map, head, _| {
11726                (
11727                    movement::indented_line_beginning(
11728                        map,
11729                        head,
11730                        action.stop_at_soft_wraps,
11731                        action.stop_at_indent,
11732                    ),
11733                    SelectionGoal::None,
11734                )
11735            });
11736        })
11737    }
11738
11739    pub fn select_to_beginning_of_line(
11740        &mut self,
11741        action: &SelectToBeginningOfLine,
11742        window: &mut Window,
11743        cx: &mut Context<Self>,
11744    ) {
11745        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11746        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11747            s.move_heads_with(|map, head, _| {
11748                (
11749                    movement::indented_line_beginning(
11750                        map,
11751                        head,
11752                        action.stop_at_soft_wraps,
11753                        action.stop_at_indent,
11754                    ),
11755                    SelectionGoal::None,
11756                )
11757            });
11758        });
11759    }
11760
11761    pub fn delete_to_beginning_of_line(
11762        &mut self,
11763        action: &DeleteToBeginningOfLine,
11764        window: &mut Window,
11765        cx: &mut Context<Self>,
11766    ) {
11767        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11768        self.transact(window, cx, |this, window, cx| {
11769            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11770                s.move_with(|_, selection| {
11771                    selection.reversed = true;
11772                });
11773            });
11774
11775            this.select_to_beginning_of_line(
11776                &SelectToBeginningOfLine {
11777                    stop_at_soft_wraps: false,
11778                    stop_at_indent: action.stop_at_indent,
11779                },
11780                window,
11781                cx,
11782            );
11783            this.backspace(&Backspace, window, cx);
11784        });
11785    }
11786
11787    pub fn move_to_end_of_line(
11788        &mut self,
11789        action: &MoveToEndOfLine,
11790        window: &mut Window,
11791        cx: &mut Context<Self>,
11792    ) {
11793        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11794        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11795            s.move_cursors_with(|map, head, _| {
11796                (
11797                    movement::line_end(map, head, action.stop_at_soft_wraps),
11798                    SelectionGoal::None,
11799                )
11800            });
11801        })
11802    }
11803
11804    pub fn select_to_end_of_line(
11805        &mut self,
11806        action: &SelectToEndOfLine,
11807        window: &mut Window,
11808        cx: &mut Context<Self>,
11809    ) {
11810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11811        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11812            s.move_heads_with(|map, head, _| {
11813                (
11814                    movement::line_end(map, head, action.stop_at_soft_wraps),
11815                    SelectionGoal::None,
11816                )
11817            });
11818        })
11819    }
11820
11821    pub fn delete_to_end_of_line(
11822        &mut self,
11823        _: &DeleteToEndOfLine,
11824        window: &mut Window,
11825        cx: &mut Context<Self>,
11826    ) {
11827        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11828        self.transact(window, cx, |this, window, cx| {
11829            this.select_to_end_of_line(
11830                &SelectToEndOfLine {
11831                    stop_at_soft_wraps: false,
11832                },
11833                window,
11834                cx,
11835            );
11836            this.delete(&Delete, window, cx);
11837        });
11838    }
11839
11840    pub fn cut_to_end_of_line(
11841        &mut self,
11842        _: &CutToEndOfLine,
11843        window: &mut Window,
11844        cx: &mut Context<Self>,
11845    ) {
11846        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11847        self.transact(window, cx, |this, window, cx| {
11848            this.select_to_end_of_line(
11849                &SelectToEndOfLine {
11850                    stop_at_soft_wraps: false,
11851                },
11852                window,
11853                cx,
11854            );
11855            this.cut(&Cut, window, cx);
11856        });
11857    }
11858
11859    pub fn move_to_start_of_paragraph(
11860        &mut self,
11861        _: &MoveToStartOfParagraph,
11862        window: &mut Window,
11863        cx: &mut Context<Self>,
11864    ) {
11865        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11866            cx.propagate();
11867            return;
11868        }
11869        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11870        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11871            s.move_with(|map, selection| {
11872                selection.collapse_to(
11873                    movement::start_of_paragraph(map, selection.head(), 1),
11874                    SelectionGoal::None,
11875                )
11876            });
11877        })
11878    }
11879
11880    pub fn move_to_end_of_paragraph(
11881        &mut self,
11882        _: &MoveToEndOfParagraph,
11883        window: &mut Window,
11884        cx: &mut Context<Self>,
11885    ) {
11886        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11887            cx.propagate();
11888            return;
11889        }
11890        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11891        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11892            s.move_with(|map, selection| {
11893                selection.collapse_to(
11894                    movement::end_of_paragraph(map, selection.head(), 1),
11895                    SelectionGoal::None,
11896                )
11897            });
11898        })
11899    }
11900
11901    pub fn select_to_start_of_paragraph(
11902        &mut self,
11903        _: &SelectToStartOfParagraph,
11904        window: &mut Window,
11905        cx: &mut Context<Self>,
11906    ) {
11907        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11908            cx.propagate();
11909            return;
11910        }
11911        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11912        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11913            s.move_heads_with(|map, head, _| {
11914                (
11915                    movement::start_of_paragraph(map, head, 1),
11916                    SelectionGoal::None,
11917                )
11918            });
11919        })
11920    }
11921
11922    pub fn select_to_end_of_paragraph(
11923        &mut self,
11924        _: &SelectToEndOfParagraph,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11929            cx.propagate();
11930            return;
11931        }
11932        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11933        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11934            s.move_heads_with(|map, head, _| {
11935                (
11936                    movement::end_of_paragraph(map, head, 1),
11937                    SelectionGoal::None,
11938                )
11939            });
11940        })
11941    }
11942
11943    pub fn move_to_start_of_excerpt(
11944        &mut self,
11945        _: &MoveToStartOfExcerpt,
11946        window: &mut Window,
11947        cx: &mut Context<Self>,
11948    ) {
11949        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11950            cx.propagate();
11951            return;
11952        }
11953        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11954        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11955            s.move_with(|map, selection| {
11956                selection.collapse_to(
11957                    movement::start_of_excerpt(
11958                        map,
11959                        selection.head(),
11960                        workspace::searchable::Direction::Prev,
11961                    ),
11962                    SelectionGoal::None,
11963                )
11964            });
11965        })
11966    }
11967
11968    pub fn move_to_start_of_next_excerpt(
11969        &mut self,
11970        _: &MoveToStartOfNextExcerpt,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) {
11974        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11975            cx.propagate();
11976            return;
11977        }
11978
11979        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11980            s.move_with(|map, selection| {
11981                selection.collapse_to(
11982                    movement::start_of_excerpt(
11983                        map,
11984                        selection.head(),
11985                        workspace::searchable::Direction::Next,
11986                    ),
11987                    SelectionGoal::None,
11988                )
11989            });
11990        })
11991    }
11992
11993    pub fn move_to_end_of_excerpt(
11994        &mut self,
11995        _: &MoveToEndOfExcerpt,
11996        window: &mut Window,
11997        cx: &mut Context<Self>,
11998    ) {
11999        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12000            cx.propagate();
12001            return;
12002        }
12003        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12004        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12005            s.move_with(|map, selection| {
12006                selection.collapse_to(
12007                    movement::end_of_excerpt(
12008                        map,
12009                        selection.head(),
12010                        workspace::searchable::Direction::Next,
12011                    ),
12012                    SelectionGoal::None,
12013                )
12014            });
12015        })
12016    }
12017
12018    pub fn move_to_end_of_previous_excerpt(
12019        &mut self,
12020        _: &MoveToEndOfPreviousExcerpt,
12021        window: &mut Window,
12022        cx: &mut Context<Self>,
12023    ) {
12024        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12025            cx.propagate();
12026            return;
12027        }
12028        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12029        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12030            s.move_with(|map, selection| {
12031                selection.collapse_to(
12032                    movement::end_of_excerpt(
12033                        map,
12034                        selection.head(),
12035                        workspace::searchable::Direction::Prev,
12036                    ),
12037                    SelectionGoal::None,
12038                )
12039            });
12040        })
12041    }
12042
12043    pub fn select_to_start_of_excerpt(
12044        &mut self,
12045        _: &SelectToStartOfExcerpt,
12046        window: &mut Window,
12047        cx: &mut Context<Self>,
12048    ) {
12049        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12050            cx.propagate();
12051            return;
12052        }
12053        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12054        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12055            s.move_heads_with(|map, head, _| {
12056                (
12057                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12058                    SelectionGoal::None,
12059                )
12060            });
12061        })
12062    }
12063
12064    pub fn select_to_start_of_next_excerpt(
12065        &mut self,
12066        _: &SelectToStartOfNextExcerpt,
12067        window: &mut Window,
12068        cx: &mut Context<Self>,
12069    ) {
12070        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12071            cx.propagate();
12072            return;
12073        }
12074        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_heads_with(|map, head, _| {
12077                (
12078                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12079                    SelectionGoal::None,
12080                )
12081            });
12082        })
12083    }
12084
12085    pub fn select_to_end_of_excerpt(
12086        &mut self,
12087        _: &SelectToEndOfExcerpt,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12092            cx.propagate();
12093            return;
12094        }
12095        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12096        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12097            s.move_heads_with(|map, head, _| {
12098                (
12099                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12100                    SelectionGoal::None,
12101                )
12102            });
12103        })
12104    }
12105
12106    pub fn select_to_end_of_previous_excerpt(
12107        &mut self,
12108        _: &SelectToEndOfPreviousExcerpt,
12109        window: &mut Window,
12110        cx: &mut Context<Self>,
12111    ) {
12112        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12113            cx.propagate();
12114            return;
12115        }
12116        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12117        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12118            s.move_heads_with(|map, head, _| {
12119                (
12120                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12121                    SelectionGoal::None,
12122                )
12123            });
12124        })
12125    }
12126
12127    pub fn move_to_beginning(
12128        &mut self,
12129        _: &MoveToBeginning,
12130        window: &mut Window,
12131        cx: &mut Context<Self>,
12132    ) {
12133        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12134            cx.propagate();
12135            return;
12136        }
12137        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12138        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12139            s.select_ranges(vec![0..0]);
12140        });
12141    }
12142
12143    pub fn select_to_beginning(
12144        &mut self,
12145        _: &SelectToBeginning,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        let mut selection = self.selections.last::<Point>(cx);
12150        selection.set_head(Point::zero(), SelectionGoal::None);
12151        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12152        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12153            s.select(vec![selection]);
12154        });
12155    }
12156
12157    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12158        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12159            cx.propagate();
12160            return;
12161        }
12162        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12163        let cursor = self.buffer.read(cx).read(cx).len();
12164        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12165            s.select_ranges(vec![cursor..cursor])
12166        });
12167    }
12168
12169    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12170        self.nav_history = nav_history;
12171    }
12172
12173    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12174        self.nav_history.as_ref()
12175    }
12176
12177    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12178        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12179    }
12180
12181    fn push_to_nav_history(
12182        &mut self,
12183        cursor_anchor: Anchor,
12184        new_position: Option<Point>,
12185        is_deactivate: bool,
12186        cx: &mut Context<Self>,
12187    ) {
12188        if let Some(nav_history) = self.nav_history.as_mut() {
12189            let buffer = self.buffer.read(cx).read(cx);
12190            let cursor_position = cursor_anchor.to_point(&buffer);
12191            let scroll_state = self.scroll_manager.anchor();
12192            let scroll_top_row = scroll_state.top_row(&buffer);
12193            drop(buffer);
12194
12195            if let Some(new_position) = new_position {
12196                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12197                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12198                    return;
12199                }
12200            }
12201
12202            nav_history.push(
12203                Some(NavigationData {
12204                    cursor_anchor,
12205                    cursor_position,
12206                    scroll_anchor: scroll_state,
12207                    scroll_top_row,
12208                }),
12209                cx,
12210            );
12211            cx.emit(EditorEvent::PushedToNavHistory {
12212                anchor: cursor_anchor,
12213                is_deactivate,
12214            })
12215        }
12216    }
12217
12218    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12219        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12220        let buffer = self.buffer.read(cx).snapshot(cx);
12221        let mut selection = self.selections.first::<usize>(cx);
12222        selection.set_head(buffer.len(), SelectionGoal::None);
12223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224            s.select(vec![selection]);
12225        });
12226    }
12227
12228    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12229        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12230        let end = self.buffer.read(cx).read(cx).len();
12231        self.change_selections(None, window, cx, |s| {
12232            s.select_ranges(vec![0..end]);
12233        });
12234    }
12235
12236    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12237        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12238        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12239        let mut selections = self.selections.all::<Point>(cx);
12240        let max_point = display_map.buffer_snapshot.max_point();
12241        for selection in &mut selections {
12242            let rows = selection.spanned_rows(true, &display_map);
12243            selection.start = Point::new(rows.start.0, 0);
12244            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12245            selection.reversed = false;
12246        }
12247        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12248            s.select(selections);
12249        });
12250    }
12251
12252    pub fn split_selection_into_lines(
12253        &mut self,
12254        _: &SplitSelectionIntoLines,
12255        window: &mut Window,
12256        cx: &mut Context<Self>,
12257    ) {
12258        let selections = self
12259            .selections
12260            .all::<Point>(cx)
12261            .into_iter()
12262            .map(|selection| selection.start..selection.end)
12263            .collect::<Vec<_>>();
12264        self.unfold_ranges(&selections, true, true, cx);
12265
12266        let mut new_selection_ranges = Vec::new();
12267        {
12268            let buffer = self.buffer.read(cx).read(cx);
12269            for selection in selections {
12270                for row in selection.start.row..selection.end.row {
12271                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12272                    new_selection_ranges.push(cursor..cursor);
12273                }
12274
12275                let is_multiline_selection = selection.start.row != selection.end.row;
12276                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12277                // so this action feels more ergonomic when paired with other selection operations
12278                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12279                if !should_skip_last {
12280                    new_selection_ranges.push(selection.end..selection.end);
12281                }
12282            }
12283        }
12284        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12285            s.select_ranges(new_selection_ranges);
12286        });
12287    }
12288
12289    pub fn add_selection_above(
12290        &mut self,
12291        _: &AddSelectionAbove,
12292        window: &mut Window,
12293        cx: &mut Context<Self>,
12294    ) {
12295        self.add_selection(true, window, cx);
12296    }
12297
12298    pub fn add_selection_below(
12299        &mut self,
12300        _: &AddSelectionBelow,
12301        window: &mut Window,
12302        cx: &mut Context<Self>,
12303    ) {
12304        self.add_selection(false, window, cx);
12305    }
12306
12307    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12308        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12309
12310        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12311        let mut selections = self.selections.all::<Point>(cx);
12312        let text_layout_details = self.text_layout_details(window);
12313        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12314            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12315            let range = oldest_selection.display_range(&display_map).sorted();
12316
12317            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12318            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12319            let positions = start_x.min(end_x)..start_x.max(end_x);
12320
12321            selections.clear();
12322            let mut stack = Vec::new();
12323            for row in range.start.row().0..=range.end.row().0 {
12324                if let Some(selection) = self.selections.build_columnar_selection(
12325                    &display_map,
12326                    DisplayRow(row),
12327                    &positions,
12328                    oldest_selection.reversed,
12329                    &text_layout_details,
12330                ) {
12331                    stack.push(selection.id);
12332                    selections.push(selection);
12333                }
12334            }
12335
12336            if above {
12337                stack.reverse();
12338            }
12339
12340            AddSelectionsState { above, stack }
12341        });
12342
12343        let last_added_selection = *state.stack.last().unwrap();
12344        let mut new_selections = Vec::new();
12345        if above == state.above {
12346            let end_row = if above {
12347                DisplayRow(0)
12348            } else {
12349                display_map.max_point().row()
12350            };
12351
12352            'outer: for selection in selections {
12353                if selection.id == last_added_selection {
12354                    let range = selection.display_range(&display_map).sorted();
12355                    debug_assert_eq!(range.start.row(), range.end.row());
12356                    let mut row = range.start.row();
12357                    let positions =
12358                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12359                            px(start)..px(end)
12360                        } else {
12361                            let start_x =
12362                                display_map.x_for_display_point(range.start, &text_layout_details);
12363                            let end_x =
12364                                display_map.x_for_display_point(range.end, &text_layout_details);
12365                            start_x.min(end_x)..start_x.max(end_x)
12366                        };
12367
12368                    while row != end_row {
12369                        if above {
12370                            row.0 -= 1;
12371                        } else {
12372                            row.0 += 1;
12373                        }
12374
12375                        if let Some(new_selection) = self.selections.build_columnar_selection(
12376                            &display_map,
12377                            row,
12378                            &positions,
12379                            selection.reversed,
12380                            &text_layout_details,
12381                        ) {
12382                            state.stack.push(new_selection.id);
12383                            if above {
12384                                new_selections.push(new_selection);
12385                                new_selections.push(selection);
12386                            } else {
12387                                new_selections.push(selection);
12388                                new_selections.push(new_selection);
12389                            }
12390
12391                            continue 'outer;
12392                        }
12393                    }
12394                }
12395
12396                new_selections.push(selection);
12397            }
12398        } else {
12399            new_selections = selections;
12400            new_selections.retain(|s| s.id != last_added_selection);
12401            state.stack.pop();
12402        }
12403
12404        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12405            s.select(new_selections);
12406        });
12407        if state.stack.len() > 1 {
12408            self.add_selections_state = Some(state);
12409        }
12410    }
12411
12412    fn select_match_ranges(
12413        &mut self,
12414        range: Range<usize>,
12415        reversed: bool,
12416        replace_newest: bool,
12417        auto_scroll: Option<Autoscroll>,
12418        window: &mut Window,
12419        cx: &mut Context<Editor>,
12420    ) {
12421        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12422        self.change_selections(auto_scroll, window, cx, |s| {
12423            if replace_newest {
12424                s.delete(s.newest_anchor().id);
12425            }
12426            if reversed {
12427                s.insert_range(range.end..range.start);
12428            } else {
12429                s.insert_range(range);
12430            }
12431        });
12432    }
12433
12434    pub fn select_next_match_internal(
12435        &mut self,
12436        display_map: &DisplaySnapshot,
12437        replace_newest: bool,
12438        autoscroll: Option<Autoscroll>,
12439        window: &mut Window,
12440        cx: &mut Context<Self>,
12441    ) -> Result<()> {
12442        let buffer = &display_map.buffer_snapshot;
12443        let mut selections = self.selections.all::<usize>(cx);
12444        if let Some(mut select_next_state) = self.select_next_state.take() {
12445            let query = &select_next_state.query;
12446            if !select_next_state.done {
12447                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12448                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12449                let mut next_selected_range = None;
12450
12451                let bytes_after_last_selection =
12452                    buffer.bytes_in_range(last_selection.end..buffer.len());
12453                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12454                let query_matches = query
12455                    .stream_find_iter(bytes_after_last_selection)
12456                    .map(|result| (last_selection.end, result))
12457                    .chain(
12458                        query
12459                            .stream_find_iter(bytes_before_first_selection)
12460                            .map(|result| (0, result)),
12461                    );
12462
12463                for (start_offset, query_match) in query_matches {
12464                    let query_match = query_match.unwrap(); // can only fail due to I/O
12465                    let offset_range =
12466                        start_offset + query_match.start()..start_offset + query_match.end();
12467                    let display_range = offset_range.start.to_display_point(display_map)
12468                        ..offset_range.end.to_display_point(display_map);
12469
12470                    if !select_next_state.wordwise
12471                        || (!movement::is_inside_word(display_map, display_range.start)
12472                            && !movement::is_inside_word(display_map, display_range.end))
12473                    {
12474                        // TODO: This is n^2, because we might check all the selections
12475                        if !selections
12476                            .iter()
12477                            .any(|selection| selection.range().overlaps(&offset_range))
12478                        {
12479                            next_selected_range = Some(offset_range);
12480                            break;
12481                        }
12482                    }
12483                }
12484
12485                if let Some(next_selected_range) = next_selected_range {
12486                    self.select_match_ranges(
12487                        next_selected_range,
12488                        last_selection.reversed,
12489                        replace_newest,
12490                        autoscroll,
12491                        window,
12492                        cx,
12493                    );
12494                } else {
12495                    select_next_state.done = true;
12496                }
12497            }
12498
12499            self.select_next_state = Some(select_next_state);
12500        } else {
12501            let mut only_carets = true;
12502            let mut same_text_selected = true;
12503            let mut selected_text = None;
12504
12505            let mut selections_iter = selections.iter().peekable();
12506            while let Some(selection) = selections_iter.next() {
12507                if selection.start != selection.end {
12508                    only_carets = false;
12509                }
12510
12511                if same_text_selected {
12512                    if selected_text.is_none() {
12513                        selected_text =
12514                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12515                    }
12516
12517                    if let Some(next_selection) = selections_iter.peek() {
12518                        if next_selection.range().len() == selection.range().len() {
12519                            let next_selected_text = buffer
12520                                .text_for_range(next_selection.range())
12521                                .collect::<String>();
12522                            if Some(next_selected_text) != selected_text {
12523                                same_text_selected = false;
12524                                selected_text = None;
12525                            }
12526                        } else {
12527                            same_text_selected = false;
12528                            selected_text = None;
12529                        }
12530                    }
12531                }
12532            }
12533
12534            if only_carets {
12535                for selection in &mut selections {
12536                    let word_range = movement::surrounding_word(
12537                        display_map,
12538                        selection.start.to_display_point(display_map),
12539                    );
12540                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12541                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12542                    selection.goal = SelectionGoal::None;
12543                    selection.reversed = false;
12544                    self.select_match_ranges(
12545                        selection.start..selection.end,
12546                        selection.reversed,
12547                        replace_newest,
12548                        autoscroll,
12549                        window,
12550                        cx,
12551                    );
12552                }
12553
12554                if selections.len() == 1 {
12555                    let selection = selections
12556                        .last()
12557                        .expect("ensured that there's only one selection");
12558                    let query = buffer
12559                        .text_for_range(selection.start..selection.end)
12560                        .collect::<String>();
12561                    let is_empty = query.is_empty();
12562                    let select_state = SelectNextState {
12563                        query: AhoCorasick::new(&[query])?,
12564                        wordwise: true,
12565                        done: is_empty,
12566                    };
12567                    self.select_next_state = Some(select_state);
12568                } else {
12569                    self.select_next_state = None;
12570                }
12571            } else if let Some(selected_text) = selected_text {
12572                self.select_next_state = Some(SelectNextState {
12573                    query: AhoCorasick::new(&[selected_text])?,
12574                    wordwise: false,
12575                    done: false,
12576                });
12577                self.select_next_match_internal(
12578                    display_map,
12579                    replace_newest,
12580                    autoscroll,
12581                    window,
12582                    cx,
12583                )?;
12584            }
12585        }
12586        Ok(())
12587    }
12588
12589    pub fn select_all_matches(
12590        &mut self,
12591        _action: &SelectAllMatches,
12592        window: &mut Window,
12593        cx: &mut Context<Self>,
12594    ) -> Result<()> {
12595        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12596
12597        self.push_to_selection_history();
12598        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12599
12600        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12601        let Some(select_next_state) = self.select_next_state.as_mut() else {
12602            return Ok(());
12603        };
12604        if select_next_state.done {
12605            return Ok(());
12606        }
12607
12608        let mut new_selections = Vec::new();
12609
12610        let reversed = self.selections.oldest::<usize>(cx).reversed;
12611        let buffer = &display_map.buffer_snapshot;
12612        let query_matches = select_next_state
12613            .query
12614            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12615
12616        for query_match in query_matches.into_iter() {
12617            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12618            let offset_range = if reversed {
12619                query_match.end()..query_match.start()
12620            } else {
12621                query_match.start()..query_match.end()
12622            };
12623            let display_range = offset_range.start.to_display_point(&display_map)
12624                ..offset_range.end.to_display_point(&display_map);
12625
12626            if !select_next_state.wordwise
12627                || (!movement::is_inside_word(&display_map, display_range.start)
12628                    && !movement::is_inside_word(&display_map, display_range.end))
12629            {
12630                new_selections.push(offset_range.start..offset_range.end);
12631            }
12632        }
12633
12634        select_next_state.done = true;
12635        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12636        self.change_selections(None, window, cx, |selections| {
12637            selections.select_ranges(new_selections)
12638        });
12639
12640        Ok(())
12641    }
12642
12643    pub fn select_next(
12644        &mut self,
12645        action: &SelectNext,
12646        window: &mut Window,
12647        cx: &mut Context<Self>,
12648    ) -> Result<()> {
12649        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12650        self.push_to_selection_history();
12651        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12652        self.select_next_match_internal(
12653            &display_map,
12654            action.replace_newest,
12655            Some(Autoscroll::newest()),
12656            window,
12657            cx,
12658        )?;
12659        Ok(())
12660    }
12661
12662    pub fn select_previous(
12663        &mut self,
12664        action: &SelectPrevious,
12665        window: &mut Window,
12666        cx: &mut Context<Self>,
12667    ) -> Result<()> {
12668        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12669        self.push_to_selection_history();
12670        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12671        let buffer = &display_map.buffer_snapshot;
12672        let mut selections = self.selections.all::<usize>(cx);
12673        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12674            let query = &select_prev_state.query;
12675            if !select_prev_state.done {
12676                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12677                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12678                let mut next_selected_range = None;
12679                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12680                let bytes_before_last_selection =
12681                    buffer.reversed_bytes_in_range(0..last_selection.start);
12682                let bytes_after_first_selection =
12683                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12684                let query_matches = query
12685                    .stream_find_iter(bytes_before_last_selection)
12686                    .map(|result| (last_selection.start, result))
12687                    .chain(
12688                        query
12689                            .stream_find_iter(bytes_after_first_selection)
12690                            .map(|result| (buffer.len(), result)),
12691                    );
12692                for (end_offset, query_match) in query_matches {
12693                    let query_match = query_match.unwrap(); // can only fail due to I/O
12694                    let offset_range =
12695                        end_offset - query_match.end()..end_offset - query_match.start();
12696                    let display_range = offset_range.start.to_display_point(&display_map)
12697                        ..offset_range.end.to_display_point(&display_map);
12698
12699                    if !select_prev_state.wordwise
12700                        || (!movement::is_inside_word(&display_map, display_range.start)
12701                            && !movement::is_inside_word(&display_map, display_range.end))
12702                    {
12703                        next_selected_range = Some(offset_range);
12704                        break;
12705                    }
12706                }
12707
12708                if let Some(next_selected_range) = next_selected_range {
12709                    self.select_match_ranges(
12710                        next_selected_range,
12711                        last_selection.reversed,
12712                        action.replace_newest,
12713                        Some(Autoscroll::newest()),
12714                        window,
12715                        cx,
12716                    );
12717                } else {
12718                    select_prev_state.done = true;
12719                }
12720            }
12721
12722            self.select_prev_state = Some(select_prev_state);
12723        } else {
12724            let mut only_carets = true;
12725            let mut same_text_selected = true;
12726            let mut selected_text = None;
12727
12728            let mut selections_iter = selections.iter().peekable();
12729            while let Some(selection) = selections_iter.next() {
12730                if selection.start != selection.end {
12731                    only_carets = false;
12732                }
12733
12734                if same_text_selected {
12735                    if selected_text.is_none() {
12736                        selected_text =
12737                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12738                    }
12739
12740                    if let Some(next_selection) = selections_iter.peek() {
12741                        if next_selection.range().len() == selection.range().len() {
12742                            let next_selected_text = buffer
12743                                .text_for_range(next_selection.range())
12744                                .collect::<String>();
12745                            if Some(next_selected_text) != selected_text {
12746                                same_text_selected = false;
12747                                selected_text = None;
12748                            }
12749                        } else {
12750                            same_text_selected = false;
12751                            selected_text = None;
12752                        }
12753                    }
12754                }
12755            }
12756
12757            if only_carets {
12758                for selection in &mut selections {
12759                    let word_range = movement::surrounding_word(
12760                        &display_map,
12761                        selection.start.to_display_point(&display_map),
12762                    );
12763                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12764                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12765                    selection.goal = SelectionGoal::None;
12766                    selection.reversed = false;
12767                    self.select_match_ranges(
12768                        selection.start..selection.end,
12769                        selection.reversed,
12770                        action.replace_newest,
12771                        Some(Autoscroll::newest()),
12772                        window,
12773                        cx,
12774                    );
12775                }
12776                if selections.len() == 1 {
12777                    let selection = selections
12778                        .last()
12779                        .expect("ensured that there's only one selection");
12780                    let query = buffer
12781                        .text_for_range(selection.start..selection.end)
12782                        .collect::<String>();
12783                    let is_empty = query.is_empty();
12784                    let select_state = SelectNextState {
12785                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12786                        wordwise: true,
12787                        done: is_empty,
12788                    };
12789                    self.select_prev_state = Some(select_state);
12790                } else {
12791                    self.select_prev_state = None;
12792                }
12793            } else if let Some(selected_text) = selected_text {
12794                self.select_prev_state = Some(SelectNextState {
12795                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12796                    wordwise: false,
12797                    done: false,
12798                });
12799                self.select_previous(action, window, cx)?;
12800            }
12801        }
12802        Ok(())
12803    }
12804
12805    pub fn find_next_match(
12806        &mut self,
12807        _: &FindNextMatch,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) -> Result<()> {
12811        let selections = self.selections.disjoint_anchors();
12812        match selections.first() {
12813            Some(first) if selections.len() >= 2 => {
12814                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12815                    s.select_ranges([first.range()]);
12816                });
12817            }
12818            _ => self.select_next(
12819                &SelectNext {
12820                    replace_newest: true,
12821                },
12822                window,
12823                cx,
12824            )?,
12825        }
12826        Ok(())
12827    }
12828
12829    pub fn find_previous_match(
12830        &mut self,
12831        _: &FindPreviousMatch,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) -> Result<()> {
12835        let selections = self.selections.disjoint_anchors();
12836        match selections.last() {
12837            Some(last) if selections.len() >= 2 => {
12838                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12839                    s.select_ranges([last.range()]);
12840                });
12841            }
12842            _ => self.select_previous(
12843                &SelectPrevious {
12844                    replace_newest: true,
12845                },
12846                window,
12847                cx,
12848            )?,
12849        }
12850        Ok(())
12851    }
12852
12853    pub fn toggle_comments(
12854        &mut self,
12855        action: &ToggleComments,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        if self.read_only(cx) {
12860            return;
12861        }
12862        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12863        let text_layout_details = &self.text_layout_details(window);
12864        self.transact(window, cx, |this, window, cx| {
12865            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
12866            let mut edits = Vec::new();
12867            let mut selection_edit_ranges = Vec::new();
12868            let mut last_toggled_row = None;
12869            let snapshot = this.buffer.read(cx).read(cx);
12870            let empty_str: Arc<str> = Arc::default();
12871            let mut suffixes_inserted = Vec::new();
12872            let ignore_indent = action.ignore_indent;
12873
12874            fn comment_prefix_range(
12875                snapshot: &MultiBufferSnapshot,
12876                row: MultiBufferRow,
12877                comment_prefix: &str,
12878                comment_prefix_whitespace: &str,
12879                ignore_indent: bool,
12880            ) -> Range<Point> {
12881                let indent_size = if ignore_indent {
12882                    0
12883                } else {
12884                    snapshot.indent_size_for_line(row).len
12885                };
12886
12887                let start = Point::new(row.0, indent_size);
12888
12889                let mut line_bytes = snapshot
12890                    .bytes_in_range(start..snapshot.max_point())
12891                    .flatten()
12892                    .copied();
12893
12894                // If this line currently begins with the line comment prefix, then record
12895                // the range containing the prefix.
12896                if line_bytes
12897                    .by_ref()
12898                    .take(comment_prefix.len())
12899                    .eq(comment_prefix.bytes())
12900                {
12901                    // Include any whitespace that matches the comment prefix.
12902                    let matching_whitespace_len = line_bytes
12903                        .zip(comment_prefix_whitespace.bytes())
12904                        .take_while(|(a, b)| a == b)
12905                        .count() as u32;
12906                    let end = Point::new(
12907                        start.row,
12908                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
12909                    );
12910                    start..end
12911                } else {
12912                    start..start
12913                }
12914            }
12915
12916            fn comment_suffix_range(
12917                snapshot: &MultiBufferSnapshot,
12918                row: MultiBufferRow,
12919                comment_suffix: &str,
12920                comment_suffix_has_leading_space: bool,
12921            ) -> Range<Point> {
12922                let end = Point::new(row.0, snapshot.line_len(row));
12923                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
12924
12925                let mut line_end_bytes = snapshot
12926                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
12927                    .flatten()
12928                    .copied();
12929
12930                let leading_space_len = if suffix_start_column > 0
12931                    && line_end_bytes.next() == Some(b' ')
12932                    && comment_suffix_has_leading_space
12933                {
12934                    1
12935                } else {
12936                    0
12937                };
12938
12939                // If this line currently begins with the line comment prefix, then record
12940                // the range containing the prefix.
12941                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
12942                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
12943                    start..end
12944                } else {
12945                    end..end
12946                }
12947            }
12948
12949            // TODO: Handle selections that cross excerpts
12950            for selection in &mut selections {
12951                let start_column = snapshot
12952                    .indent_size_for_line(MultiBufferRow(selection.start.row))
12953                    .len;
12954                let language = if let Some(language) =
12955                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
12956                {
12957                    language
12958                } else {
12959                    continue;
12960                };
12961
12962                selection_edit_ranges.clear();
12963
12964                // If multiple selections contain a given row, avoid processing that
12965                // row more than once.
12966                let mut start_row = MultiBufferRow(selection.start.row);
12967                if last_toggled_row == Some(start_row) {
12968                    start_row = start_row.next_row();
12969                }
12970                let end_row =
12971                    if selection.end.row > selection.start.row && selection.end.column == 0 {
12972                        MultiBufferRow(selection.end.row - 1)
12973                    } else {
12974                        MultiBufferRow(selection.end.row)
12975                    };
12976                last_toggled_row = Some(end_row);
12977
12978                if start_row > end_row {
12979                    continue;
12980                }
12981
12982                // If the language has line comments, toggle those.
12983                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
12984
12985                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
12986                if ignore_indent {
12987                    full_comment_prefixes = full_comment_prefixes
12988                        .into_iter()
12989                        .map(|s| Arc::from(s.trim_end()))
12990                        .collect();
12991                }
12992
12993                if !full_comment_prefixes.is_empty() {
12994                    let first_prefix = full_comment_prefixes
12995                        .first()
12996                        .expect("prefixes is non-empty");
12997                    let prefix_trimmed_lengths = full_comment_prefixes
12998                        .iter()
12999                        .map(|p| p.trim_end_matches(' ').len())
13000                        .collect::<SmallVec<[usize; 4]>>();
13001
13002                    let mut all_selection_lines_are_comments = true;
13003
13004                    for row in start_row.0..=end_row.0 {
13005                        let row = MultiBufferRow(row);
13006                        if start_row < end_row && snapshot.is_line_blank(row) {
13007                            continue;
13008                        }
13009
13010                        let prefix_range = full_comment_prefixes
13011                            .iter()
13012                            .zip(prefix_trimmed_lengths.iter().copied())
13013                            .map(|(prefix, trimmed_prefix_len)| {
13014                                comment_prefix_range(
13015                                    snapshot.deref(),
13016                                    row,
13017                                    &prefix[..trimmed_prefix_len],
13018                                    &prefix[trimmed_prefix_len..],
13019                                    ignore_indent,
13020                                )
13021                            })
13022                            .max_by_key(|range| range.end.column - range.start.column)
13023                            .expect("prefixes is non-empty");
13024
13025                        if prefix_range.is_empty() {
13026                            all_selection_lines_are_comments = false;
13027                        }
13028
13029                        selection_edit_ranges.push(prefix_range);
13030                    }
13031
13032                    if all_selection_lines_are_comments {
13033                        edits.extend(
13034                            selection_edit_ranges
13035                                .iter()
13036                                .cloned()
13037                                .map(|range| (range, empty_str.clone())),
13038                        );
13039                    } else {
13040                        let min_column = selection_edit_ranges
13041                            .iter()
13042                            .map(|range| range.start.column)
13043                            .min()
13044                            .unwrap_or(0);
13045                        edits.extend(selection_edit_ranges.iter().map(|range| {
13046                            let position = Point::new(range.start.row, min_column);
13047                            (position..position, first_prefix.clone())
13048                        }));
13049                    }
13050                } else if let Some((full_comment_prefix, comment_suffix)) =
13051                    language.block_comment_delimiters()
13052                {
13053                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13054                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13055                    let prefix_range = comment_prefix_range(
13056                        snapshot.deref(),
13057                        start_row,
13058                        comment_prefix,
13059                        comment_prefix_whitespace,
13060                        ignore_indent,
13061                    );
13062                    let suffix_range = comment_suffix_range(
13063                        snapshot.deref(),
13064                        end_row,
13065                        comment_suffix.trim_start_matches(' '),
13066                        comment_suffix.starts_with(' '),
13067                    );
13068
13069                    if prefix_range.is_empty() || suffix_range.is_empty() {
13070                        edits.push((
13071                            prefix_range.start..prefix_range.start,
13072                            full_comment_prefix.clone(),
13073                        ));
13074                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13075                        suffixes_inserted.push((end_row, comment_suffix.len()));
13076                    } else {
13077                        edits.push((prefix_range, empty_str.clone()));
13078                        edits.push((suffix_range, empty_str.clone()));
13079                    }
13080                } else {
13081                    continue;
13082                }
13083            }
13084
13085            drop(snapshot);
13086            this.buffer.update(cx, |buffer, cx| {
13087                buffer.edit(edits, None, cx);
13088            });
13089
13090            // Adjust selections so that they end before any comment suffixes that
13091            // were inserted.
13092            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13093            let mut selections = this.selections.all::<Point>(cx);
13094            let snapshot = this.buffer.read(cx).read(cx);
13095            for selection in &mut selections {
13096                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13097                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13098                        Ordering::Less => {
13099                            suffixes_inserted.next();
13100                            continue;
13101                        }
13102                        Ordering::Greater => break,
13103                        Ordering::Equal => {
13104                            if selection.end.column == snapshot.line_len(row) {
13105                                if selection.is_empty() {
13106                                    selection.start.column -= suffix_len as u32;
13107                                }
13108                                selection.end.column -= suffix_len as u32;
13109                            }
13110                            break;
13111                        }
13112                    }
13113                }
13114            }
13115
13116            drop(snapshot);
13117            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13118                s.select(selections)
13119            });
13120
13121            let selections = this.selections.all::<Point>(cx);
13122            let selections_on_single_row = selections.windows(2).all(|selections| {
13123                selections[0].start.row == selections[1].start.row
13124                    && selections[0].end.row == selections[1].end.row
13125                    && selections[0].start.row == selections[0].end.row
13126            });
13127            let selections_selecting = selections
13128                .iter()
13129                .any(|selection| selection.start != selection.end);
13130            let advance_downwards = action.advance_downwards
13131                && selections_on_single_row
13132                && !selections_selecting
13133                && !matches!(this.mode, EditorMode::SingleLine { .. });
13134
13135            if advance_downwards {
13136                let snapshot = this.buffer.read(cx).snapshot(cx);
13137
13138                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13139                    s.move_cursors_with(|display_snapshot, display_point, _| {
13140                        let mut point = display_point.to_point(display_snapshot);
13141                        point.row += 1;
13142                        point = snapshot.clip_point(point, Bias::Left);
13143                        let display_point = point.to_display_point(display_snapshot);
13144                        let goal = SelectionGoal::HorizontalPosition(
13145                            display_snapshot
13146                                .x_for_display_point(display_point, text_layout_details)
13147                                .into(),
13148                        );
13149                        (display_point, goal)
13150                    })
13151                });
13152            }
13153        });
13154    }
13155
13156    pub fn select_enclosing_symbol(
13157        &mut self,
13158        _: &SelectEnclosingSymbol,
13159        window: &mut Window,
13160        cx: &mut Context<Self>,
13161    ) {
13162        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13163
13164        let buffer = self.buffer.read(cx).snapshot(cx);
13165        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13166
13167        fn update_selection(
13168            selection: &Selection<usize>,
13169            buffer_snap: &MultiBufferSnapshot,
13170        ) -> Option<Selection<usize>> {
13171            let cursor = selection.head();
13172            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13173            for symbol in symbols.iter().rev() {
13174                let start = symbol.range.start.to_offset(buffer_snap);
13175                let end = symbol.range.end.to_offset(buffer_snap);
13176                let new_range = start..end;
13177                if start < selection.start || end > selection.end {
13178                    return Some(Selection {
13179                        id: selection.id,
13180                        start: new_range.start,
13181                        end: new_range.end,
13182                        goal: SelectionGoal::None,
13183                        reversed: selection.reversed,
13184                    });
13185                }
13186            }
13187            None
13188        }
13189
13190        let mut selected_larger_symbol = false;
13191        let new_selections = old_selections
13192            .iter()
13193            .map(|selection| match update_selection(selection, &buffer) {
13194                Some(new_selection) => {
13195                    if new_selection.range() != selection.range() {
13196                        selected_larger_symbol = true;
13197                    }
13198                    new_selection
13199                }
13200                None => selection.clone(),
13201            })
13202            .collect::<Vec<_>>();
13203
13204        if selected_larger_symbol {
13205            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13206                s.select(new_selections);
13207            });
13208        }
13209    }
13210
13211    pub fn select_larger_syntax_node(
13212        &mut self,
13213        _: &SelectLargerSyntaxNode,
13214        window: &mut Window,
13215        cx: &mut Context<Self>,
13216    ) {
13217        let Some(visible_row_count) = self.visible_row_count() else {
13218            return;
13219        };
13220        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13221        if old_selections.is_empty() {
13222            return;
13223        }
13224
13225        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13226
13227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13228        let buffer = self.buffer.read(cx).snapshot(cx);
13229
13230        let mut selected_larger_node = false;
13231        let mut new_selections = old_selections
13232            .iter()
13233            .map(|selection| {
13234                let old_range = selection.start..selection.end;
13235
13236                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13237                    // manually select word at selection
13238                    if ["string_content", "inline"].contains(&node.kind()) {
13239                        let word_range = {
13240                            let display_point = buffer
13241                                .offset_to_point(old_range.start)
13242                                .to_display_point(&display_map);
13243                            let Range { start, end } =
13244                                movement::surrounding_word(&display_map, display_point);
13245                            start.to_point(&display_map).to_offset(&buffer)
13246                                ..end.to_point(&display_map).to_offset(&buffer)
13247                        };
13248                        // ignore if word is already selected
13249                        if !word_range.is_empty() && old_range != word_range {
13250                            let last_word_range = {
13251                                let display_point = buffer
13252                                    .offset_to_point(old_range.end)
13253                                    .to_display_point(&display_map);
13254                                let Range { start, end } =
13255                                    movement::surrounding_word(&display_map, display_point);
13256                                start.to_point(&display_map).to_offset(&buffer)
13257                                    ..end.to_point(&display_map).to_offset(&buffer)
13258                            };
13259                            // only select word if start and end point belongs to same word
13260                            if word_range == last_word_range {
13261                                selected_larger_node = true;
13262                                return Selection {
13263                                    id: selection.id,
13264                                    start: word_range.start,
13265                                    end: word_range.end,
13266                                    goal: SelectionGoal::None,
13267                                    reversed: selection.reversed,
13268                                };
13269                            }
13270                        }
13271                    }
13272                }
13273
13274                let mut new_range = old_range.clone();
13275                while let Some((_node, containing_range)) =
13276                    buffer.syntax_ancestor(new_range.clone())
13277                {
13278                    new_range = match containing_range {
13279                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13280                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13281                    };
13282                    if !display_map.intersects_fold(new_range.start)
13283                        && !display_map.intersects_fold(new_range.end)
13284                    {
13285                        break;
13286                    }
13287                }
13288
13289                selected_larger_node |= new_range != old_range;
13290                Selection {
13291                    id: selection.id,
13292                    start: new_range.start,
13293                    end: new_range.end,
13294                    goal: SelectionGoal::None,
13295                    reversed: selection.reversed,
13296                }
13297            })
13298            .collect::<Vec<_>>();
13299
13300        if !selected_larger_node {
13301            return; // don't put this call in the history
13302        }
13303
13304        // scroll based on transformation done to the last selection created by the user
13305        let (last_old, last_new) = old_selections
13306            .last()
13307            .zip(new_selections.last().cloned())
13308            .expect("old_selections isn't empty");
13309
13310        // revert selection
13311        let is_selection_reversed = {
13312            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13313            new_selections.last_mut().expect("checked above").reversed =
13314                should_newest_selection_be_reversed;
13315            should_newest_selection_be_reversed
13316        };
13317
13318        if selected_larger_node {
13319            self.select_syntax_node_history.disable_clearing = true;
13320            self.change_selections(None, window, cx, |s| {
13321                s.select(new_selections.clone());
13322            });
13323            self.select_syntax_node_history.disable_clearing = false;
13324        }
13325
13326        let start_row = last_new.start.to_display_point(&display_map).row().0;
13327        let end_row = last_new.end.to_display_point(&display_map).row().0;
13328        let selection_height = end_row - start_row + 1;
13329        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13330
13331        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13332        let scroll_behavior = if fits_on_the_screen {
13333            self.request_autoscroll(Autoscroll::fit(), cx);
13334            SelectSyntaxNodeScrollBehavior::FitSelection
13335        } else if is_selection_reversed {
13336            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13337            SelectSyntaxNodeScrollBehavior::CursorTop
13338        } else {
13339            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13340            SelectSyntaxNodeScrollBehavior::CursorBottom
13341        };
13342
13343        self.select_syntax_node_history.push((
13344            old_selections,
13345            scroll_behavior,
13346            is_selection_reversed,
13347        ));
13348    }
13349
13350    pub fn select_smaller_syntax_node(
13351        &mut self,
13352        _: &SelectSmallerSyntaxNode,
13353        window: &mut Window,
13354        cx: &mut Context<Self>,
13355    ) {
13356        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13357
13358        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13359            self.select_syntax_node_history.pop()
13360        {
13361            if let Some(selection) = selections.last_mut() {
13362                selection.reversed = is_selection_reversed;
13363            }
13364
13365            self.select_syntax_node_history.disable_clearing = true;
13366            self.change_selections(None, window, cx, |s| {
13367                s.select(selections.to_vec());
13368            });
13369            self.select_syntax_node_history.disable_clearing = false;
13370
13371            match scroll_behavior {
13372                SelectSyntaxNodeScrollBehavior::CursorTop => {
13373                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13374                }
13375                SelectSyntaxNodeScrollBehavior::FitSelection => {
13376                    self.request_autoscroll(Autoscroll::fit(), cx);
13377                }
13378                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13379                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13380                }
13381            }
13382        }
13383    }
13384
13385    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13386        if !EditorSettings::get_global(cx).gutter.runnables {
13387            self.clear_tasks();
13388            return Task::ready(());
13389        }
13390        let project = self.project.as_ref().map(Entity::downgrade);
13391        let task_sources = self.lsp_task_sources(cx);
13392        cx.spawn_in(window, async move |editor, cx| {
13393            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13394            let Some(project) = project.and_then(|p| p.upgrade()) else {
13395                return;
13396            };
13397            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13398                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13399            }) else {
13400                return;
13401            };
13402
13403            let hide_runnables = project
13404                .update(cx, |project, cx| {
13405                    // Do not display any test indicators in non-dev server remote projects.
13406                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13407                })
13408                .unwrap_or(true);
13409            if hide_runnables {
13410                return;
13411            }
13412            let new_rows =
13413                cx.background_spawn({
13414                    let snapshot = display_snapshot.clone();
13415                    async move {
13416                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13417                    }
13418                })
13419                    .await;
13420            let Ok(lsp_tasks) =
13421                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13422            else {
13423                return;
13424            };
13425            let lsp_tasks = lsp_tasks.await;
13426
13427            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13428                lsp_tasks
13429                    .into_iter()
13430                    .flat_map(|(kind, tasks)| {
13431                        tasks.into_iter().filter_map(move |(location, task)| {
13432                            Some((kind.clone(), location?, task))
13433                        })
13434                    })
13435                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13436                        let buffer = location.target.buffer;
13437                        let buffer_snapshot = buffer.read(cx).snapshot();
13438                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13439                            |(excerpt_id, snapshot, _)| {
13440                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13441                                    display_snapshot
13442                                        .buffer_snapshot
13443                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13444                                } else {
13445                                    None
13446                                }
13447                            },
13448                        );
13449                        if let Some(offset) = offset {
13450                            let task_buffer_range =
13451                                location.target.range.to_point(&buffer_snapshot);
13452                            let context_buffer_range =
13453                                task_buffer_range.to_offset(&buffer_snapshot);
13454                            let context_range = BufferOffset(context_buffer_range.start)
13455                                ..BufferOffset(context_buffer_range.end);
13456
13457                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13458                                .or_insert_with(|| RunnableTasks {
13459                                    templates: Vec::new(),
13460                                    offset,
13461                                    column: task_buffer_range.start.column,
13462                                    extra_variables: HashMap::default(),
13463                                    context_range,
13464                                })
13465                                .templates
13466                                .push((kind, task.original_task().clone()));
13467                        }
13468
13469                        acc
13470                    })
13471            }) else {
13472                return;
13473            };
13474
13475            let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
13476            editor
13477                .update(cx, |editor, _| {
13478                    editor.clear_tasks();
13479                    for (key, mut value) in rows {
13480                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13481                            value.templates.extend(lsp_tasks.templates);
13482                        }
13483
13484                        editor.insert_tasks(key, value);
13485                    }
13486                    for (key, value) in lsp_tasks_by_rows {
13487                        editor.insert_tasks(key, value);
13488                    }
13489                })
13490                .ok();
13491        })
13492    }
13493    fn fetch_runnable_ranges(
13494        snapshot: &DisplaySnapshot,
13495        range: Range<Anchor>,
13496    ) -> Vec<language::RunnableRange> {
13497        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13498    }
13499
13500    fn runnable_rows(
13501        project: Entity<Project>,
13502        snapshot: DisplaySnapshot,
13503        runnable_ranges: Vec<RunnableRange>,
13504        mut cx: AsyncWindowContext,
13505    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13506        runnable_ranges
13507            .into_iter()
13508            .filter_map(|mut runnable| {
13509                let tasks = cx
13510                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13511                    .ok()?;
13512                if tasks.is_empty() {
13513                    return None;
13514                }
13515
13516                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13517
13518                let row = snapshot
13519                    .buffer_snapshot
13520                    .buffer_line_for_row(MultiBufferRow(point.row))?
13521                    .1
13522                    .start
13523                    .row;
13524
13525                let context_range =
13526                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13527                Some((
13528                    (runnable.buffer_id, row),
13529                    RunnableTasks {
13530                        templates: tasks,
13531                        offset: snapshot
13532                            .buffer_snapshot
13533                            .anchor_before(runnable.run_range.start),
13534                        context_range,
13535                        column: point.column,
13536                        extra_variables: runnable.extra_captures,
13537                    },
13538                ))
13539            })
13540            .collect()
13541    }
13542
13543    fn templates_with_tags(
13544        project: &Entity<Project>,
13545        runnable: &mut Runnable,
13546        cx: &mut App,
13547    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13548        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13549            let (worktree_id, file) = project
13550                .buffer_for_id(runnable.buffer, cx)
13551                .and_then(|buffer| buffer.read(cx).file())
13552                .map(|file| (file.worktree_id(cx), file.clone()))
13553                .unzip();
13554
13555            (
13556                project.task_store().read(cx).task_inventory().cloned(),
13557                worktree_id,
13558                file,
13559            )
13560        });
13561
13562        let mut templates_with_tags = mem::take(&mut runnable.tags)
13563            .into_iter()
13564            .flat_map(|RunnableTag(tag)| {
13565                inventory
13566                    .as_ref()
13567                    .into_iter()
13568                    .flat_map(|inventory| {
13569                        inventory.read(cx).list_tasks(
13570                            file.clone(),
13571                            Some(runnable.language.clone()),
13572                            worktree_id,
13573                            cx,
13574                        )
13575                    })
13576                    .filter(move |(_, template)| {
13577                        template.tags.iter().any(|source_tag| source_tag == &tag)
13578                    })
13579            })
13580            .sorted_by_key(|(kind, _)| kind.to_owned())
13581            .collect::<Vec<_>>();
13582        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13583            // Strongest source wins; if we have worktree tag binding, prefer that to
13584            // global and language bindings;
13585            // if we have a global binding, prefer that to language binding.
13586            let first_mismatch = templates_with_tags
13587                .iter()
13588                .position(|(tag_source, _)| tag_source != leading_tag_source);
13589            if let Some(index) = first_mismatch {
13590                templates_with_tags.truncate(index);
13591            }
13592        }
13593
13594        templates_with_tags
13595    }
13596
13597    pub fn move_to_enclosing_bracket(
13598        &mut self,
13599        _: &MoveToEnclosingBracket,
13600        window: &mut Window,
13601        cx: &mut Context<Self>,
13602    ) {
13603        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13604        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13605            s.move_offsets_with(|snapshot, selection| {
13606                let Some(enclosing_bracket_ranges) =
13607                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13608                else {
13609                    return;
13610                };
13611
13612                let mut best_length = usize::MAX;
13613                let mut best_inside = false;
13614                let mut best_in_bracket_range = false;
13615                let mut best_destination = None;
13616                for (open, close) in enclosing_bracket_ranges {
13617                    let close = close.to_inclusive();
13618                    let length = close.end() - open.start;
13619                    let inside = selection.start >= open.end && selection.end <= *close.start();
13620                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13621                        || close.contains(&selection.head());
13622
13623                    // If best is next to a bracket and current isn't, skip
13624                    if !in_bracket_range && best_in_bracket_range {
13625                        continue;
13626                    }
13627
13628                    // Prefer smaller lengths unless best is inside and current isn't
13629                    if length > best_length && (best_inside || !inside) {
13630                        continue;
13631                    }
13632
13633                    best_length = length;
13634                    best_inside = inside;
13635                    best_in_bracket_range = in_bracket_range;
13636                    best_destination = Some(
13637                        if close.contains(&selection.start) && close.contains(&selection.end) {
13638                            if inside { open.end } else { open.start }
13639                        } else if inside {
13640                            *close.start()
13641                        } else {
13642                            *close.end()
13643                        },
13644                    );
13645                }
13646
13647                if let Some(destination) = best_destination {
13648                    selection.collapse_to(destination, SelectionGoal::None);
13649                }
13650            })
13651        });
13652    }
13653
13654    pub fn undo_selection(
13655        &mut self,
13656        _: &UndoSelection,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13661        self.end_selection(window, cx);
13662        self.selection_history.mode = SelectionHistoryMode::Undoing;
13663        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13664            self.change_selections(None, window, cx, |s| {
13665                s.select_anchors(entry.selections.to_vec())
13666            });
13667            self.select_next_state = entry.select_next_state;
13668            self.select_prev_state = entry.select_prev_state;
13669            self.add_selections_state = entry.add_selections_state;
13670            self.request_autoscroll(Autoscroll::newest(), cx);
13671        }
13672        self.selection_history.mode = SelectionHistoryMode::Normal;
13673    }
13674
13675    pub fn redo_selection(
13676        &mut self,
13677        _: &RedoSelection,
13678        window: &mut Window,
13679        cx: &mut Context<Self>,
13680    ) {
13681        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13682        self.end_selection(window, cx);
13683        self.selection_history.mode = SelectionHistoryMode::Redoing;
13684        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13685            self.change_selections(None, window, cx, |s| {
13686                s.select_anchors(entry.selections.to_vec())
13687            });
13688            self.select_next_state = entry.select_next_state;
13689            self.select_prev_state = entry.select_prev_state;
13690            self.add_selections_state = entry.add_selections_state;
13691            self.request_autoscroll(Autoscroll::newest(), cx);
13692        }
13693        self.selection_history.mode = SelectionHistoryMode::Normal;
13694    }
13695
13696    pub fn expand_excerpts(
13697        &mut self,
13698        action: &ExpandExcerpts,
13699        _: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13703    }
13704
13705    pub fn expand_excerpts_down(
13706        &mut self,
13707        action: &ExpandExcerptsDown,
13708        _: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13712    }
13713
13714    pub fn expand_excerpts_up(
13715        &mut self,
13716        action: &ExpandExcerptsUp,
13717        _: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13721    }
13722
13723    pub fn expand_excerpts_for_direction(
13724        &mut self,
13725        lines: u32,
13726        direction: ExpandExcerptDirection,
13727
13728        cx: &mut Context<Self>,
13729    ) {
13730        let selections = self.selections.disjoint_anchors();
13731
13732        let lines = if lines == 0 {
13733            EditorSettings::get_global(cx).expand_excerpt_lines
13734        } else {
13735            lines
13736        };
13737
13738        self.buffer.update(cx, |buffer, cx| {
13739            let snapshot = buffer.snapshot(cx);
13740            let mut excerpt_ids = selections
13741                .iter()
13742                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13743                .collect::<Vec<_>>();
13744            excerpt_ids.sort();
13745            excerpt_ids.dedup();
13746            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13747        })
13748    }
13749
13750    pub fn expand_excerpt(
13751        &mut self,
13752        excerpt: ExcerptId,
13753        direction: ExpandExcerptDirection,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) {
13757        let current_scroll_position = self.scroll_position(cx);
13758        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13759        let mut should_scroll_up = false;
13760
13761        if direction == ExpandExcerptDirection::Down {
13762            let multi_buffer = self.buffer.read(cx);
13763            let snapshot = multi_buffer.snapshot(cx);
13764            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13765                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13766                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13767                        let buffer_snapshot = buffer.read(cx).snapshot();
13768                        let excerpt_end_row =
13769                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13770                        let last_row = buffer_snapshot.max_point().row;
13771                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13772                        should_scroll_up = lines_below >= lines_to_expand;
13773                    }
13774                }
13775            }
13776        }
13777
13778        self.buffer.update(cx, |buffer, cx| {
13779            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13780        });
13781
13782        if should_scroll_up {
13783            let new_scroll_position =
13784                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13785            self.set_scroll_position(new_scroll_position, window, cx);
13786        }
13787    }
13788
13789    pub fn go_to_singleton_buffer_point(
13790        &mut self,
13791        point: Point,
13792        window: &mut Window,
13793        cx: &mut Context<Self>,
13794    ) {
13795        self.go_to_singleton_buffer_range(point..point, window, cx);
13796    }
13797
13798    pub fn go_to_singleton_buffer_range(
13799        &mut self,
13800        range: Range<Point>,
13801        window: &mut Window,
13802        cx: &mut Context<Self>,
13803    ) {
13804        let multibuffer = self.buffer().read(cx);
13805        let Some(buffer) = multibuffer.as_singleton() else {
13806            return;
13807        };
13808        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13809            return;
13810        };
13811        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13812            return;
13813        };
13814        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13815            s.select_anchor_ranges([start..end])
13816        });
13817    }
13818
13819    pub fn go_to_diagnostic(
13820        &mut self,
13821        _: &GoToDiagnostic,
13822        window: &mut Window,
13823        cx: &mut Context<Self>,
13824    ) {
13825        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13826        self.go_to_diagnostic_impl(Direction::Next, window, cx)
13827    }
13828
13829    pub fn go_to_prev_diagnostic(
13830        &mut self,
13831        _: &GoToPreviousDiagnostic,
13832        window: &mut Window,
13833        cx: &mut Context<Self>,
13834    ) {
13835        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13836        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
13837    }
13838
13839    pub fn go_to_diagnostic_impl(
13840        &mut self,
13841        direction: Direction,
13842        window: &mut Window,
13843        cx: &mut Context<Self>,
13844    ) {
13845        let buffer = self.buffer.read(cx).snapshot(cx);
13846        let selection = self.selections.newest::<usize>(cx);
13847
13848        let mut active_group_id = None;
13849        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
13850            if active_group.active_range.start.to_offset(&buffer) == selection.start {
13851                active_group_id = Some(active_group.group_id);
13852            }
13853        }
13854
13855        fn filtered(
13856            snapshot: EditorSnapshot,
13857            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
13858        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
13859            diagnostics
13860                .filter(|entry| entry.range.start != entry.range.end)
13861                .filter(|entry| !entry.diagnostic.is_unnecessary)
13862                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
13863        }
13864
13865        let snapshot = self.snapshot(window, cx);
13866        let before = filtered(
13867            snapshot.clone(),
13868            buffer
13869                .diagnostics_in_range(0..selection.start)
13870                .filter(|entry| entry.range.start <= selection.start),
13871        );
13872        let after = filtered(
13873            snapshot,
13874            buffer
13875                .diagnostics_in_range(selection.start..buffer.len())
13876                .filter(|entry| entry.range.start >= selection.start),
13877        );
13878
13879        let mut found: Option<DiagnosticEntry<usize>> = None;
13880        if direction == Direction::Prev {
13881            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
13882            {
13883                for diagnostic in prev_diagnostics.into_iter().rev() {
13884                    if diagnostic.range.start != selection.start
13885                        || active_group_id
13886                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
13887                    {
13888                        found = Some(diagnostic);
13889                        break 'outer;
13890                    }
13891                }
13892            }
13893        } else {
13894            for diagnostic in after.chain(before) {
13895                if diagnostic.range.start != selection.start
13896                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
13897                {
13898                    found = Some(diagnostic);
13899                    break;
13900                }
13901            }
13902        }
13903        let Some(next_diagnostic) = found else {
13904            return;
13905        };
13906
13907        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
13908            return;
13909        };
13910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13911            s.select_ranges(vec![
13912                next_diagnostic.range.start..next_diagnostic.range.start,
13913            ])
13914        });
13915        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
13916        self.refresh_inline_completion(false, true, window, cx);
13917    }
13918
13919    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
13920        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13921        let snapshot = self.snapshot(window, cx);
13922        let selection = self.selections.newest::<Point>(cx);
13923        self.go_to_hunk_before_or_after_position(
13924            &snapshot,
13925            selection.head(),
13926            Direction::Next,
13927            window,
13928            cx,
13929        );
13930    }
13931
13932    pub fn go_to_hunk_before_or_after_position(
13933        &mut self,
13934        snapshot: &EditorSnapshot,
13935        position: Point,
13936        direction: Direction,
13937        window: &mut Window,
13938        cx: &mut Context<Editor>,
13939    ) {
13940        let row = if direction == Direction::Next {
13941            self.hunk_after_position(snapshot, position)
13942                .map(|hunk| hunk.row_range.start)
13943        } else {
13944            self.hunk_before_position(snapshot, position)
13945        };
13946
13947        if let Some(row) = row {
13948            let destination = Point::new(row.0, 0);
13949            let autoscroll = Autoscroll::center();
13950
13951            self.unfold_ranges(&[destination..destination], false, false, cx);
13952            self.change_selections(Some(autoscroll), window, cx, |s| {
13953                s.select_ranges([destination..destination]);
13954            });
13955        }
13956    }
13957
13958    fn hunk_after_position(
13959        &mut self,
13960        snapshot: &EditorSnapshot,
13961        position: Point,
13962    ) -> Option<MultiBufferDiffHunk> {
13963        snapshot
13964            .buffer_snapshot
13965            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
13966            .find(|hunk| hunk.row_range.start.0 > position.row)
13967            .or_else(|| {
13968                snapshot
13969                    .buffer_snapshot
13970                    .diff_hunks_in_range(Point::zero()..position)
13971                    .find(|hunk| hunk.row_range.end.0 < position.row)
13972            })
13973    }
13974
13975    fn go_to_prev_hunk(
13976        &mut self,
13977        _: &GoToPreviousHunk,
13978        window: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13982        let snapshot = self.snapshot(window, cx);
13983        let selection = self.selections.newest::<Point>(cx);
13984        self.go_to_hunk_before_or_after_position(
13985            &snapshot,
13986            selection.head(),
13987            Direction::Prev,
13988            window,
13989            cx,
13990        );
13991    }
13992
13993    fn hunk_before_position(
13994        &mut self,
13995        snapshot: &EditorSnapshot,
13996        position: Point,
13997    ) -> Option<MultiBufferRow> {
13998        snapshot
13999            .buffer_snapshot
14000            .diff_hunk_before(position)
14001            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14002    }
14003
14004    fn go_to_next_change(
14005        &mut self,
14006        _: &GoToNextChange,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        if let Some(selections) = self
14011            .change_list
14012            .next_change(1, Direction::Next)
14013            .map(|s| s.to_vec())
14014        {
14015            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14016                let map = s.display_map();
14017                s.select_display_ranges(selections.iter().map(|a| {
14018                    let point = a.to_display_point(&map);
14019                    point..point
14020                }))
14021            })
14022        }
14023    }
14024
14025    fn go_to_previous_change(
14026        &mut self,
14027        _: &GoToPreviousChange,
14028        window: &mut Window,
14029        cx: &mut Context<Self>,
14030    ) {
14031        if let Some(selections) = self
14032            .change_list
14033            .next_change(1, Direction::Prev)
14034            .map(|s| s.to_vec())
14035        {
14036            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14037                let map = s.display_map();
14038                s.select_display_ranges(selections.iter().map(|a| {
14039                    let point = a.to_display_point(&map);
14040                    point..point
14041                }))
14042            })
14043        }
14044    }
14045
14046    fn go_to_line<T: 'static>(
14047        &mut self,
14048        position: Anchor,
14049        highlight_color: Option<Hsla>,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        let snapshot = self.snapshot(window, cx).display_snapshot;
14054        let position = position.to_point(&snapshot.buffer_snapshot);
14055        let start = snapshot
14056            .buffer_snapshot
14057            .clip_point(Point::new(position.row, 0), Bias::Left);
14058        let end = start + Point::new(1, 0);
14059        let start = snapshot.buffer_snapshot.anchor_before(start);
14060        let end = snapshot.buffer_snapshot.anchor_before(end);
14061
14062        self.highlight_rows::<T>(
14063            start..end,
14064            highlight_color
14065                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14066            Default::default(),
14067            cx,
14068        );
14069
14070        if self.buffer.read(cx).is_singleton() {
14071            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14072        }
14073    }
14074
14075    pub fn go_to_definition(
14076        &mut self,
14077        _: &GoToDefinition,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) -> Task<Result<Navigated>> {
14081        let definition =
14082            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14083        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14084        cx.spawn_in(window, async move |editor, cx| {
14085            if definition.await? == Navigated::Yes {
14086                return Ok(Navigated::Yes);
14087            }
14088            match fallback_strategy {
14089                GoToDefinitionFallback::None => Ok(Navigated::No),
14090                GoToDefinitionFallback::FindAllReferences => {
14091                    match editor.update_in(cx, |editor, window, cx| {
14092                        editor.find_all_references(&FindAllReferences, window, cx)
14093                    })? {
14094                        Some(references) => references.await,
14095                        None => Ok(Navigated::No),
14096                    }
14097                }
14098            }
14099        })
14100    }
14101
14102    pub fn go_to_declaration(
14103        &mut self,
14104        _: &GoToDeclaration,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) -> Task<Result<Navigated>> {
14108        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14109    }
14110
14111    pub fn go_to_declaration_split(
14112        &mut self,
14113        _: &GoToDeclaration,
14114        window: &mut Window,
14115        cx: &mut Context<Self>,
14116    ) -> Task<Result<Navigated>> {
14117        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14118    }
14119
14120    pub fn go_to_implementation(
14121        &mut self,
14122        _: &GoToImplementation,
14123        window: &mut Window,
14124        cx: &mut Context<Self>,
14125    ) -> Task<Result<Navigated>> {
14126        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14127    }
14128
14129    pub fn go_to_implementation_split(
14130        &mut self,
14131        _: &GoToImplementationSplit,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) -> Task<Result<Navigated>> {
14135        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14136    }
14137
14138    pub fn go_to_type_definition(
14139        &mut self,
14140        _: &GoToTypeDefinition,
14141        window: &mut Window,
14142        cx: &mut Context<Self>,
14143    ) -> Task<Result<Navigated>> {
14144        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14145    }
14146
14147    pub fn go_to_definition_split(
14148        &mut self,
14149        _: &GoToDefinitionSplit,
14150        window: &mut Window,
14151        cx: &mut Context<Self>,
14152    ) -> Task<Result<Navigated>> {
14153        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14154    }
14155
14156    pub fn go_to_type_definition_split(
14157        &mut self,
14158        _: &GoToTypeDefinitionSplit,
14159        window: &mut Window,
14160        cx: &mut Context<Self>,
14161    ) -> Task<Result<Navigated>> {
14162        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14163    }
14164
14165    fn go_to_definition_of_kind(
14166        &mut self,
14167        kind: GotoDefinitionKind,
14168        split: bool,
14169        window: &mut Window,
14170        cx: &mut Context<Self>,
14171    ) -> Task<Result<Navigated>> {
14172        let Some(provider) = self.semantics_provider.clone() else {
14173            return Task::ready(Ok(Navigated::No));
14174        };
14175        let head = self.selections.newest::<usize>(cx).head();
14176        let buffer = self.buffer.read(cx);
14177        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14178            text_anchor
14179        } else {
14180            return Task::ready(Ok(Navigated::No));
14181        };
14182
14183        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14184            return Task::ready(Ok(Navigated::No));
14185        };
14186
14187        cx.spawn_in(window, async move |editor, cx| {
14188            let definitions = definitions.await?;
14189            let navigated = editor
14190                .update_in(cx, |editor, window, cx| {
14191                    editor.navigate_to_hover_links(
14192                        Some(kind),
14193                        definitions
14194                            .into_iter()
14195                            .filter(|location| {
14196                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14197                            })
14198                            .map(HoverLink::Text)
14199                            .collect::<Vec<_>>(),
14200                        split,
14201                        window,
14202                        cx,
14203                    )
14204                })?
14205                .await?;
14206            anyhow::Ok(navigated)
14207        })
14208    }
14209
14210    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14211        let selection = self.selections.newest_anchor();
14212        let head = selection.head();
14213        let tail = selection.tail();
14214
14215        let Some((buffer, start_position)) =
14216            self.buffer.read(cx).text_anchor_for_position(head, cx)
14217        else {
14218            return;
14219        };
14220
14221        let end_position = if head != tail {
14222            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14223                return;
14224            };
14225            Some(pos)
14226        } else {
14227            None
14228        };
14229
14230        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14231            let url = if let Some(end_pos) = end_position {
14232                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14233            } else {
14234                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14235            };
14236
14237            if let Some(url) = url {
14238                editor.update(cx, |_, cx| {
14239                    cx.open_url(&url);
14240                })
14241            } else {
14242                Ok(())
14243            }
14244        });
14245
14246        url_finder.detach();
14247    }
14248
14249    pub fn open_selected_filename(
14250        &mut self,
14251        _: &OpenSelectedFilename,
14252        window: &mut Window,
14253        cx: &mut Context<Self>,
14254    ) {
14255        let Some(workspace) = self.workspace() else {
14256            return;
14257        };
14258
14259        let position = self.selections.newest_anchor().head();
14260
14261        let Some((buffer, buffer_position)) =
14262            self.buffer.read(cx).text_anchor_for_position(position, cx)
14263        else {
14264            return;
14265        };
14266
14267        let project = self.project.clone();
14268
14269        cx.spawn_in(window, async move |_, cx| {
14270            let result = find_file(&buffer, project, buffer_position, cx).await;
14271
14272            if let Some((_, path)) = result {
14273                workspace
14274                    .update_in(cx, |workspace, window, cx| {
14275                        workspace.open_resolved_path(path, window, cx)
14276                    })?
14277                    .await?;
14278            }
14279            anyhow::Ok(())
14280        })
14281        .detach();
14282    }
14283
14284    pub(crate) fn navigate_to_hover_links(
14285        &mut self,
14286        kind: Option<GotoDefinitionKind>,
14287        mut definitions: Vec<HoverLink>,
14288        split: bool,
14289        window: &mut Window,
14290        cx: &mut Context<Editor>,
14291    ) -> Task<Result<Navigated>> {
14292        // If there is one definition, just open it directly
14293        if definitions.len() == 1 {
14294            let definition = definitions.pop().unwrap();
14295
14296            enum TargetTaskResult {
14297                Location(Option<Location>),
14298                AlreadyNavigated,
14299            }
14300
14301            let target_task = match definition {
14302                HoverLink::Text(link) => {
14303                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14304                }
14305                HoverLink::InlayHint(lsp_location, server_id) => {
14306                    let computation =
14307                        self.compute_target_location(lsp_location, server_id, window, cx);
14308                    cx.background_spawn(async move {
14309                        let location = computation.await?;
14310                        Ok(TargetTaskResult::Location(location))
14311                    })
14312                }
14313                HoverLink::Url(url) => {
14314                    cx.open_url(&url);
14315                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14316                }
14317                HoverLink::File(path) => {
14318                    if let Some(workspace) = self.workspace() {
14319                        cx.spawn_in(window, async move |_, cx| {
14320                            workspace
14321                                .update_in(cx, |workspace, window, cx| {
14322                                    workspace.open_resolved_path(path, window, cx)
14323                                })?
14324                                .await
14325                                .map(|_| TargetTaskResult::AlreadyNavigated)
14326                        })
14327                    } else {
14328                        Task::ready(Ok(TargetTaskResult::Location(None)))
14329                    }
14330                }
14331            };
14332            cx.spawn_in(window, async move |editor, cx| {
14333                let target = match target_task.await.context("target resolution task")? {
14334                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14335                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14336                    TargetTaskResult::Location(Some(target)) => target,
14337                };
14338
14339                editor.update_in(cx, |editor, window, cx| {
14340                    let Some(workspace) = editor.workspace() else {
14341                        return Navigated::No;
14342                    };
14343                    let pane = workspace.read(cx).active_pane().clone();
14344
14345                    let range = target.range.to_point(target.buffer.read(cx));
14346                    let range = editor.range_for_match(&range);
14347                    let range = collapse_multiline_range(range);
14348
14349                    if !split
14350                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14351                    {
14352                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14353                    } else {
14354                        window.defer(cx, move |window, cx| {
14355                            let target_editor: Entity<Self> =
14356                                workspace.update(cx, |workspace, cx| {
14357                                    let pane = if split {
14358                                        workspace.adjacent_pane(window, cx)
14359                                    } else {
14360                                        workspace.active_pane().clone()
14361                                    };
14362
14363                                    workspace.open_project_item(
14364                                        pane,
14365                                        target.buffer.clone(),
14366                                        true,
14367                                        true,
14368                                        window,
14369                                        cx,
14370                                    )
14371                                });
14372                            target_editor.update(cx, |target_editor, cx| {
14373                                // When selecting a definition in a different buffer, disable the nav history
14374                                // to avoid creating a history entry at the previous cursor location.
14375                                pane.update(cx, |pane, _| pane.disable_history());
14376                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14377                                pane.update(cx, |pane, _| pane.enable_history());
14378                            });
14379                        });
14380                    }
14381                    Navigated::Yes
14382                })
14383            })
14384        } else if !definitions.is_empty() {
14385            cx.spawn_in(window, async move |editor, cx| {
14386                let (title, location_tasks, workspace) = editor
14387                    .update_in(cx, |editor, window, cx| {
14388                        let tab_kind = match kind {
14389                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14390                            _ => "Definitions",
14391                        };
14392                        let title = definitions
14393                            .iter()
14394                            .find_map(|definition| match definition {
14395                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14396                                    let buffer = origin.buffer.read(cx);
14397                                    format!(
14398                                        "{} for {}",
14399                                        tab_kind,
14400                                        buffer
14401                                            .text_for_range(origin.range.clone())
14402                                            .collect::<String>()
14403                                    )
14404                                }),
14405                                HoverLink::InlayHint(_, _) => None,
14406                                HoverLink::Url(_) => None,
14407                                HoverLink::File(_) => None,
14408                            })
14409                            .unwrap_or(tab_kind.to_string());
14410                        let location_tasks = definitions
14411                            .into_iter()
14412                            .map(|definition| match definition {
14413                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14414                                HoverLink::InlayHint(lsp_location, server_id) => editor
14415                                    .compute_target_location(lsp_location, server_id, window, cx),
14416                                HoverLink::Url(_) => Task::ready(Ok(None)),
14417                                HoverLink::File(_) => Task::ready(Ok(None)),
14418                            })
14419                            .collect::<Vec<_>>();
14420                        (title, location_tasks, editor.workspace().clone())
14421                    })
14422                    .context("location tasks preparation")?;
14423
14424                let locations = future::join_all(location_tasks)
14425                    .await
14426                    .into_iter()
14427                    .filter_map(|location| location.transpose())
14428                    .collect::<Result<_>>()
14429                    .context("location tasks")?;
14430
14431                let Some(workspace) = workspace else {
14432                    return Ok(Navigated::No);
14433                };
14434                let opened = workspace
14435                    .update_in(cx, |workspace, window, cx| {
14436                        Self::open_locations_in_multibuffer(
14437                            workspace,
14438                            locations,
14439                            title,
14440                            split,
14441                            MultibufferSelectionMode::First,
14442                            window,
14443                            cx,
14444                        )
14445                    })
14446                    .ok();
14447
14448                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14449            })
14450        } else {
14451            Task::ready(Ok(Navigated::No))
14452        }
14453    }
14454
14455    fn compute_target_location(
14456        &self,
14457        lsp_location: lsp::Location,
14458        server_id: LanguageServerId,
14459        window: &mut Window,
14460        cx: &mut Context<Self>,
14461    ) -> Task<anyhow::Result<Option<Location>>> {
14462        let Some(project) = self.project.clone() else {
14463            return Task::ready(Ok(None));
14464        };
14465
14466        cx.spawn_in(window, async move |editor, cx| {
14467            let location_task = editor.update(cx, |_, cx| {
14468                project.update(cx, |project, cx| {
14469                    let language_server_name = project
14470                        .language_server_statuses(cx)
14471                        .find(|(id, _)| server_id == *id)
14472                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14473                    language_server_name.map(|language_server_name| {
14474                        project.open_local_buffer_via_lsp(
14475                            lsp_location.uri.clone(),
14476                            server_id,
14477                            language_server_name,
14478                            cx,
14479                        )
14480                    })
14481                })
14482            })?;
14483            let location = match location_task {
14484                Some(task) => Some({
14485                    let target_buffer_handle = task.await.context("open local buffer")?;
14486                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
14487                        let target_start = target_buffer
14488                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14489                        let target_end = target_buffer
14490                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14491                        target_buffer.anchor_after(target_start)
14492                            ..target_buffer.anchor_before(target_end)
14493                    })?;
14494                    Location {
14495                        buffer: target_buffer_handle,
14496                        range,
14497                    }
14498                }),
14499                None => None,
14500            };
14501            Ok(location)
14502        })
14503    }
14504
14505    pub fn find_all_references(
14506        &mut self,
14507        _: &FindAllReferences,
14508        window: &mut Window,
14509        cx: &mut Context<Self>,
14510    ) -> Option<Task<Result<Navigated>>> {
14511        let selection = self.selections.newest::<usize>(cx);
14512        let multi_buffer = self.buffer.read(cx);
14513        let head = selection.head();
14514
14515        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14516        let head_anchor = multi_buffer_snapshot.anchor_at(
14517            head,
14518            if head < selection.tail() {
14519                Bias::Right
14520            } else {
14521                Bias::Left
14522            },
14523        );
14524
14525        match self
14526            .find_all_references_task_sources
14527            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14528        {
14529            Ok(_) => {
14530                log::info!(
14531                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14532                );
14533                return None;
14534            }
14535            Err(i) => {
14536                self.find_all_references_task_sources.insert(i, head_anchor);
14537            }
14538        }
14539
14540        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14541        let workspace = self.workspace()?;
14542        let project = workspace.read(cx).project().clone();
14543        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14544        Some(cx.spawn_in(window, async move |editor, cx| {
14545            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14546                if let Ok(i) = editor
14547                    .find_all_references_task_sources
14548                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14549                {
14550                    editor.find_all_references_task_sources.remove(i);
14551                }
14552            });
14553
14554            let locations = references.await?;
14555            if locations.is_empty() {
14556                return anyhow::Ok(Navigated::No);
14557            }
14558
14559            workspace.update_in(cx, |workspace, window, cx| {
14560                let title = locations
14561                    .first()
14562                    .as_ref()
14563                    .map(|location| {
14564                        let buffer = location.buffer.read(cx);
14565                        format!(
14566                            "References to `{}`",
14567                            buffer
14568                                .text_for_range(location.range.clone())
14569                                .collect::<String>()
14570                        )
14571                    })
14572                    .unwrap();
14573                Self::open_locations_in_multibuffer(
14574                    workspace,
14575                    locations,
14576                    title,
14577                    false,
14578                    MultibufferSelectionMode::First,
14579                    window,
14580                    cx,
14581                );
14582                Navigated::Yes
14583            })
14584        }))
14585    }
14586
14587    /// Opens a multibuffer with the given project locations in it
14588    pub fn open_locations_in_multibuffer(
14589        workspace: &mut Workspace,
14590        mut locations: Vec<Location>,
14591        title: String,
14592        split: bool,
14593        multibuffer_selection_mode: MultibufferSelectionMode,
14594        window: &mut Window,
14595        cx: &mut Context<Workspace>,
14596    ) {
14597        // If there are multiple definitions, open them in a multibuffer
14598        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14599        let mut locations = locations.into_iter().peekable();
14600        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14601        let capability = workspace.project().read(cx).capability();
14602
14603        let excerpt_buffer = cx.new(|cx| {
14604            let mut multibuffer = MultiBuffer::new(capability);
14605            while let Some(location) = locations.next() {
14606                let buffer = location.buffer.read(cx);
14607                let mut ranges_for_buffer = Vec::new();
14608                let range = location.range.to_point(buffer);
14609                ranges_for_buffer.push(range.clone());
14610
14611                while let Some(next_location) = locations.peek() {
14612                    if next_location.buffer == location.buffer {
14613                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14614                        locations.next();
14615                    } else {
14616                        break;
14617                    }
14618                }
14619
14620                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14621                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14622                    PathKey::for_buffer(&location.buffer, cx),
14623                    location.buffer.clone(),
14624                    ranges_for_buffer,
14625                    DEFAULT_MULTIBUFFER_CONTEXT,
14626                    cx,
14627                );
14628                ranges.extend(new_ranges)
14629            }
14630
14631            multibuffer.with_title(title)
14632        });
14633
14634        let editor = cx.new(|cx| {
14635            Editor::for_multibuffer(
14636                excerpt_buffer,
14637                Some(workspace.project().clone()),
14638                window,
14639                cx,
14640            )
14641        });
14642        editor.update(cx, |editor, cx| {
14643            match multibuffer_selection_mode {
14644                MultibufferSelectionMode::First => {
14645                    if let Some(first_range) = ranges.first() {
14646                        editor.change_selections(None, window, cx, |selections| {
14647                            selections.clear_disjoint();
14648                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14649                        });
14650                    }
14651                    editor.highlight_background::<Self>(
14652                        &ranges,
14653                        |theme| theme.editor_highlighted_line_background,
14654                        cx,
14655                    );
14656                }
14657                MultibufferSelectionMode::All => {
14658                    editor.change_selections(None, window, cx, |selections| {
14659                        selections.clear_disjoint();
14660                        selections.select_anchor_ranges(ranges);
14661                    });
14662                }
14663            }
14664            editor.register_buffers_with_language_servers(cx);
14665        });
14666
14667        let item = Box::new(editor);
14668        let item_id = item.item_id();
14669
14670        if split {
14671            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14672        } else {
14673            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14674                let (preview_item_id, preview_item_idx) =
14675                    workspace.active_pane().update(cx, |pane, _| {
14676                        (pane.preview_item_id(), pane.preview_item_idx())
14677                    });
14678
14679                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14680
14681                if let Some(preview_item_id) = preview_item_id {
14682                    workspace.active_pane().update(cx, |pane, cx| {
14683                        pane.remove_item(preview_item_id, false, false, window, cx);
14684                    });
14685                }
14686            } else {
14687                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14688            }
14689        }
14690        workspace.active_pane().update(cx, |pane, cx| {
14691            pane.set_preview_item_id(Some(item_id), cx);
14692        });
14693    }
14694
14695    pub fn rename(
14696        &mut self,
14697        _: &Rename,
14698        window: &mut Window,
14699        cx: &mut Context<Self>,
14700    ) -> Option<Task<Result<()>>> {
14701        use language::ToOffset as _;
14702
14703        let provider = self.semantics_provider.clone()?;
14704        let selection = self.selections.newest_anchor().clone();
14705        let (cursor_buffer, cursor_buffer_position) = self
14706            .buffer
14707            .read(cx)
14708            .text_anchor_for_position(selection.head(), cx)?;
14709        let (tail_buffer, cursor_buffer_position_end) = self
14710            .buffer
14711            .read(cx)
14712            .text_anchor_for_position(selection.tail(), cx)?;
14713        if tail_buffer != cursor_buffer {
14714            return None;
14715        }
14716
14717        let snapshot = cursor_buffer.read(cx).snapshot();
14718        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14719        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14720        let prepare_rename = provider
14721            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14722            .unwrap_or_else(|| Task::ready(Ok(None)));
14723        drop(snapshot);
14724
14725        Some(cx.spawn_in(window, async move |this, cx| {
14726            let rename_range = if let Some(range) = prepare_rename.await? {
14727                Some(range)
14728            } else {
14729                this.update(cx, |this, cx| {
14730                    let buffer = this.buffer.read(cx).snapshot(cx);
14731                    let mut buffer_highlights = this
14732                        .document_highlights_for_position(selection.head(), &buffer)
14733                        .filter(|highlight| {
14734                            highlight.start.excerpt_id == selection.head().excerpt_id
14735                                && highlight.end.excerpt_id == selection.head().excerpt_id
14736                        });
14737                    buffer_highlights
14738                        .next()
14739                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14740                })?
14741            };
14742            if let Some(rename_range) = rename_range {
14743                this.update_in(cx, |this, window, cx| {
14744                    let snapshot = cursor_buffer.read(cx).snapshot();
14745                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14746                    let cursor_offset_in_rename_range =
14747                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14748                    let cursor_offset_in_rename_range_end =
14749                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14750
14751                    this.take_rename(false, window, cx);
14752                    let buffer = this.buffer.read(cx).read(cx);
14753                    let cursor_offset = selection.head().to_offset(&buffer);
14754                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14755                    let rename_end = rename_start + rename_buffer_range.len();
14756                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14757                    let mut old_highlight_id = None;
14758                    let old_name: Arc<str> = buffer
14759                        .chunks(rename_start..rename_end, true)
14760                        .map(|chunk| {
14761                            if old_highlight_id.is_none() {
14762                                old_highlight_id = chunk.syntax_highlight_id;
14763                            }
14764                            chunk.text
14765                        })
14766                        .collect::<String>()
14767                        .into();
14768
14769                    drop(buffer);
14770
14771                    // Position the selection in the rename editor so that it matches the current selection.
14772                    this.show_local_selections = false;
14773                    let rename_editor = cx.new(|cx| {
14774                        let mut editor = Editor::single_line(window, cx);
14775                        editor.buffer.update(cx, |buffer, cx| {
14776                            buffer.edit([(0..0, old_name.clone())], None, cx)
14777                        });
14778                        let rename_selection_range = match cursor_offset_in_rename_range
14779                            .cmp(&cursor_offset_in_rename_range_end)
14780                        {
14781                            Ordering::Equal => {
14782                                editor.select_all(&SelectAll, window, cx);
14783                                return editor;
14784                            }
14785                            Ordering::Less => {
14786                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14787                            }
14788                            Ordering::Greater => {
14789                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14790                            }
14791                        };
14792                        if rename_selection_range.end > old_name.len() {
14793                            editor.select_all(&SelectAll, window, cx);
14794                        } else {
14795                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14796                                s.select_ranges([rename_selection_range]);
14797                            });
14798                        }
14799                        editor
14800                    });
14801                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14802                        if e == &EditorEvent::Focused {
14803                            cx.emit(EditorEvent::FocusedIn)
14804                        }
14805                    })
14806                    .detach();
14807
14808                    let write_highlights =
14809                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14810                    let read_highlights =
14811                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14812                    let ranges = write_highlights
14813                        .iter()
14814                        .flat_map(|(_, ranges)| ranges.iter())
14815                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14816                        .cloned()
14817                        .collect();
14818
14819                    this.highlight_text::<Rename>(
14820                        ranges,
14821                        HighlightStyle {
14822                            fade_out: Some(0.6),
14823                            ..Default::default()
14824                        },
14825                        cx,
14826                    );
14827                    let rename_focus_handle = rename_editor.focus_handle(cx);
14828                    window.focus(&rename_focus_handle);
14829                    let block_id = this.insert_blocks(
14830                        [BlockProperties {
14831                            style: BlockStyle::Flex,
14832                            placement: BlockPlacement::Below(range.start),
14833                            height: Some(1),
14834                            render: Arc::new({
14835                                let rename_editor = rename_editor.clone();
14836                                move |cx: &mut BlockContext| {
14837                                    let mut text_style = cx.editor_style.text.clone();
14838                                    if let Some(highlight_style) = old_highlight_id
14839                                        .and_then(|h| h.style(&cx.editor_style.syntax))
14840                                    {
14841                                        text_style = text_style.highlight(highlight_style);
14842                                    }
14843                                    div()
14844                                        .block_mouse_down()
14845                                        .pl(cx.anchor_x)
14846                                        .child(EditorElement::new(
14847                                            &rename_editor,
14848                                            EditorStyle {
14849                                                background: cx.theme().system().transparent,
14850                                                local_player: cx.editor_style.local_player,
14851                                                text: text_style,
14852                                                scrollbar_width: cx.editor_style.scrollbar_width,
14853                                                syntax: cx.editor_style.syntax.clone(),
14854                                                status: cx.editor_style.status.clone(),
14855                                                inlay_hints_style: HighlightStyle {
14856                                                    font_weight: Some(FontWeight::BOLD),
14857                                                    ..make_inlay_hints_style(cx.app)
14858                                                },
14859                                                inline_completion_styles: make_suggestion_styles(
14860                                                    cx.app,
14861                                                ),
14862                                                ..EditorStyle::default()
14863                                            },
14864                                        ))
14865                                        .into_any_element()
14866                                }
14867                            }),
14868                            priority: 0,
14869                            render_in_minimap: true,
14870                        }],
14871                        Some(Autoscroll::fit()),
14872                        cx,
14873                    )[0];
14874                    this.pending_rename = Some(RenameState {
14875                        range,
14876                        old_name,
14877                        editor: rename_editor,
14878                        block_id,
14879                    });
14880                })?;
14881            }
14882
14883            Ok(())
14884        }))
14885    }
14886
14887    pub fn confirm_rename(
14888        &mut self,
14889        _: &ConfirmRename,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) -> Option<Task<Result<()>>> {
14893        let rename = self.take_rename(false, window, cx)?;
14894        let workspace = self.workspace()?.downgrade();
14895        let (buffer, start) = self
14896            .buffer
14897            .read(cx)
14898            .text_anchor_for_position(rename.range.start, cx)?;
14899        let (end_buffer, _) = self
14900            .buffer
14901            .read(cx)
14902            .text_anchor_for_position(rename.range.end, cx)?;
14903        if buffer != end_buffer {
14904            return None;
14905        }
14906
14907        let old_name = rename.old_name;
14908        let new_name = rename.editor.read(cx).text(cx);
14909
14910        let rename = self.semantics_provider.as_ref()?.perform_rename(
14911            &buffer,
14912            start,
14913            new_name.clone(),
14914            cx,
14915        )?;
14916
14917        Some(cx.spawn_in(window, async move |editor, cx| {
14918            let project_transaction = rename.await?;
14919            Self::open_project_transaction(
14920                &editor,
14921                workspace,
14922                project_transaction,
14923                format!("Rename: {}{}", old_name, new_name),
14924                cx,
14925            )
14926            .await?;
14927
14928            editor.update(cx, |editor, cx| {
14929                editor.refresh_document_highlights(cx);
14930            })?;
14931            Ok(())
14932        }))
14933    }
14934
14935    fn take_rename(
14936        &mut self,
14937        moving_cursor: bool,
14938        window: &mut Window,
14939        cx: &mut Context<Self>,
14940    ) -> Option<RenameState> {
14941        let rename = self.pending_rename.take()?;
14942        if rename.editor.focus_handle(cx).is_focused(window) {
14943            window.focus(&self.focus_handle);
14944        }
14945
14946        self.remove_blocks(
14947            [rename.block_id].into_iter().collect(),
14948            Some(Autoscroll::fit()),
14949            cx,
14950        );
14951        self.clear_highlights::<Rename>(cx);
14952        self.show_local_selections = true;
14953
14954        if moving_cursor {
14955            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
14956                editor.selections.newest::<usize>(cx).head()
14957            });
14958
14959            // Update the selection to match the position of the selection inside
14960            // the rename editor.
14961            let snapshot = self.buffer.read(cx).read(cx);
14962            let rename_range = rename.range.to_offset(&snapshot);
14963            let cursor_in_editor = snapshot
14964                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
14965                .min(rename_range.end);
14966            drop(snapshot);
14967
14968            self.change_selections(None, window, cx, |s| {
14969                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
14970            });
14971        } else {
14972            self.refresh_document_highlights(cx);
14973        }
14974
14975        Some(rename)
14976    }
14977
14978    pub fn pending_rename(&self) -> Option<&RenameState> {
14979        self.pending_rename.as_ref()
14980    }
14981
14982    fn format(
14983        &mut self,
14984        _: &Format,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) -> Option<Task<Result<()>>> {
14988        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
14989
14990        let project = match &self.project {
14991            Some(project) => project.clone(),
14992            None => return None,
14993        };
14994
14995        Some(self.perform_format(
14996            project,
14997            FormatTrigger::Manual,
14998            FormatTarget::Buffers,
14999            window,
15000            cx,
15001        ))
15002    }
15003
15004    fn format_selections(
15005        &mut self,
15006        _: &FormatSelections,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) -> Option<Task<Result<()>>> {
15010        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15011
15012        let project = match &self.project {
15013            Some(project) => project.clone(),
15014            None => return None,
15015        };
15016
15017        let ranges = self
15018            .selections
15019            .all_adjusted(cx)
15020            .into_iter()
15021            .map(|selection| selection.range())
15022            .collect_vec();
15023
15024        Some(self.perform_format(
15025            project,
15026            FormatTrigger::Manual,
15027            FormatTarget::Ranges(ranges),
15028            window,
15029            cx,
15030        ))
15031    }
15032
15033    fn perform_format(
15034        &mut self,
15035        project: Entity<Project>,
15036        trigger: FormatTrigger,
15037        target: FormatTarget,
15038        window: &mut Window,
15039        cx: &mut Context<Self>,
15040    ) -> Task<Result<()>> {
15041        let buffer = self.buffer.clone();
15042        let (buffers, target) = match target {
15043            FormatTarget::Buffers => {
15044                let mut buffers = buffer.read(cx).all_buffers();
15045                if trigger == FormatTrigger::Save {
15046                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15047                }
15048                (buffers, LspFormatTarget::Buffers)
15049            }
15050            FormatTarget::Ranges(selection_ranges) => {
15051                let multi_buffer = buffer.read(cx);
15052                let snapshot = multi_buffer.read(cx);
15053                let mut buffers = HashSet::default();
15054                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15055                    BTreeMap::new();
15056                for selection_range in selection_ranges {
15057                    for (buffer, buffer_range, _) in
15058                        snapshot.range_to_buffer_ranges(selection_range)
15059                    {
15060                        let buffer_id = buffer.remote_id();
15061                        let start = buffer.anchor_before(buffer_range.start);
15062                        let end = buffer.anchor_after(buffer_range.end);
15063                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15064                        buffer_id_to_ranges
15065                            .entry(buffer_id)
15066                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15067                            .or_insert_with(|| vec![start..end]);
15068                    }
15069                }
15070                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15071            }
15072        };
15073
15074        let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
15075        let selections_prev = transaction_id_prev
15076            .and_then(|transaction_id_prev| {
15077                // default to selections as they were after the last edit, if we have them,
15078                // instead of how they are now.
15079                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15080                // will take you back to where you made the last edit, instead of staying where you scrolled
15081                self.selection_history
15082                    .transaction(transaction_id_prev)
15083                    .map(|t| t.0.clone())
15084            })
15085            .unwrap_or_else(|| {
15086                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15087                self.selections.disjoint_anchors()
15088            });
15089
15090        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15091        let format = project.update(cx, |project, cx| {
15092            project.format(buffers, target, true, trigger, cx)
15093        });
15094
15095        cx.spawn_in(window, async move |editor, cx| {
15096            let transaction = futures::select_biased! {
15097                transaction = format.log_err().fuse() => transaction,
15098                () = timeout => {
15099                    log::warn!("timed out waiting for formatting");
15100                    None
15101                }
15102            };
15103
15104            buffer
15105                .update(cx, |buffer, cx| {
15106                    if let Some(transaction) = transaction {
15107                        if !buffer.is_singleton() {
15108                            buffer.push_transaction(&transaction.0, cx);
15109                        }
15110                    }
15111                    cx.notify();
15112                })
15113                .ok();
15114
15115            if let Some(transaction_id_now) =
15116                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15117            {
15118                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15119                if has_new_transaction {
15120                    _ = editor.update(cx, |editor, _| {
15121                        editor
15122                            .selection_history
15123                            .insert_transaction(transaction_id_now, selections_prev);
15124                    });
15125                }
15126            }
15127
15128            Ok(())
15129        })
15130    }
15131
15132    fn organize_imports(
15133        &mut self,
15134        _: &OrganizeImports,
15135        window: &mut Window,
15136        cx: &mut Context<Self>,
15137    ) -> Option<Task<Result<()>>> {
15138        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15139        let project = match &self.project {
15140            Some(project) => project.clone(),
15141            None => return None,
15142        };
15143        Some(self.perform_code_action_kind(
15144            project,
15145            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15146            window,
15147            cx,
15148        ))
15149    }
15150
15151    fn perform_code_action_kind(
15152        &mut self,
15153        project: Entity<Project>,
15154        kind: CodeActionKind,
15155        window: &mut Window,
15156        cx: &mut Context<Self>,
15157    ) -> Task<Result<()>> {
15158        let buffer = self.buffer.clone();
15159        let buffers = buffer.read(cx).all_buffers();
15160        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15161        let apply_action = project.update(cx, |project, cx| {
15162            project.apply_code_action_kind(buffers, kind, true, cx)
15163        });
15164        cx.spawn_in(window, async move |_, cx| {
15165            let transaction = futures::select_biased! {
15166                () = timeout => {
15167                    log::warn!("timed out waiting for executing code action");
15168                    None
15169                }
15170                transaction = apply_action.log_err().fuse() => transaction,
15171            };
15172            buffer
15173                .update(cx, |buffer, cx| {
15174                    // check if we need this
15175                    if let Some(transaction) = transaction {
15176                        if !buffer.is_singleton() {
15177                            buffer.push_transaction(&transaction.0, cx);
15178                        }
15179                    }
15180                    cx.notify();
15181                })
15182                .ok();
15183            Ok(())
15184        })
15185    }
15186
15187    fn restart_language_server(
15188        &mut self,
15189        _: &RestartLanguageServer,
15190        _: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        if let Some(project) = self.project.clone() {
15194            self.buffer.update(cx, |multi_buffer, cx| {
15195                project.update(cx, |project, cx| {
15196                    project.restart_language_servers_for_buffers(
15197                        multi_buffer.all_buffers().into_iter().collect(),
15198                        cx,
15199                    );
15200                });
15201            })
15202        }
15203    }
15204
15205    fn stop_language_server(
15206        &mut self,
15207        _: &StopLanguageServer,
15208        _: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        if let Some(project) = self.project.clone() {
15212            self.buffer.update(cx, |multi_buffer, cx| {
15213                project.update(cx, |project, cx| {
15214                    project.stop_language_servers_for_buffers(
15215                        multi_buffer.all_buffers().into_iter().collect(),
15216                        cx,
15217                    );
15218                    cx.emit(project::Event::RefreshInlayHints);
15219                });
15220            });
15221        }
15222    }
15223
15224    fn cancel_language_server_work(
15225        workspace: &mut Workspace,
15226        _: &actions::CancelLanguageServerWork,
15227        _: &mut Window,
15228        cx: &mut Context<Workspace>,
15229    ) {
15230        let project = workspace.project();
15231        let buffers = workspace
15232            .active_item(cx)
15233            .and_then(|item| item.act_as::<Editor>(cx))
15234            .map_or(HashSet::default(), |editor| {
15235                editor.read(cx).buffer.read(cx).all_buffers()
15236            });
15237        project.update(cx, |project, cx| {
15238            project.cancel_language_server_work_for_buffers(buffers, cx);
15239        });
15240    }
15241
15242    fn show_character_palette(
15243        &mut self,
15244        _: &ShowCharacterPalette,
15245        window: &mut Window,
15246        _: &mut Context<Self>,
15247    ) {
15248        window.show_character_palette();
15249    }
15250
15251    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15252        if self.mode.is_minimap() {
15253            return;
15254        }
15255
15256        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15257            let buffer = self.buffer.read(cx).snapshot(cx);
15258            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15259            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15260            let is_valid = buffer
15261                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15262                .any(|entry| {
15263                    entry.diagnostic.is_primary
15264                        && !entry.range.is_empty()
15265                        && entry.range.start == primary_range_start
15266                        && entry.diagnostic.message == active_diagnostics.active_message
15267                });
15268
15269            if !is_valid {
15270                self.dismiss_diagnostics(cx);
15271            }
15272        }
15273    }
15274
15275    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15276        match &self.active_diagnostics {
15277            ActiveDiagnostic::Group(group) => Some(group),
15278            _ => None,
15279        }
15280    }
15281
15282    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15283        self.dismiss_diagnostics(cx);
15284        self.active_diagnostics = ActiveDiagnostic::All;
15285    }
15286
15287    fn activate_diagnostics(
15288        &mut self,
15289        buffer_id: BufferId,
15290        diagnostic: DiagnosticEntry<usize>,
15291        window: &mut Window,
15292        cx: &mut Context<Self>,
15293    ) {
15294        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15295            return;
15296        }
15297        self.dismiss_diagnostics(cx);
15298        let snapshot = self.snapshot(window, cx);
15299        let buffer = self.buffer.read(cx).snapshot(cx);
15300        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15301            return;
15302        };
15303
15304        let diagnostic_group = buffer
15305            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15306            .collect::<Vec<_>>();
15307
15308        let blocks =
15309            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15310
15311        let blocks = self.display_map.update(cx, |display_map, cx| {
15312            display_map.insert_blocks(blocks, cx).into_iter().collect()
15313        });
15314        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15315            active_range: buffer.anchor_before(diagnostic.range.start)
15316                ..buffer.anchor_after(diagnostic.range.end),
15317            active_message: diagnostic.diagnostic.message.clone(),
15318            group_id: diagnostic.diagnostic.group_id,
15319            blocks,
15320        });
15321        cx.notify();
15322    }
15323
15324    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15325        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15326            return;
15327        };
15328
15329        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15330        if let ActiveDiagnostic::Group(group) = prev {
15331            self.display_map.update(cx, |display_map, cx| {
15332                display_map.remove_blocks(group.blocks, cx);
15333            });
15334            cx.notify();
15335        }
15336    }
15337
15338    /// Disable inline diagnostics rendering for this editor.
15339    pub fn disable_inline_diagnostics(&mut self) {
15340        self.inline_diagnostics_enabled = false;
15341        self.inline_diagnostics_update = Task::ready(());
15342        self.inline_diagnostics.clear();
15343    }
15344
15345    pub fn diagnostics_enabled(&self) -> bool {
15346        self.mode.is_full()
15347    }
15348
15349    pub fn inline_diagnostics_enabled(&self) -> bool {
15350        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15351    }
15352
15353    pub fn show_inline_diagnostics(&self) -> bool {
15354        self.show_inline_diagnostics
15355    }
15356
15357    pub fn toggle_inline_diagnostics(
15358        &mut self,
15359        _: &ToggleInlineDiagnostics,
15360        window: &mut Window,
15361        cx: &mut Context<Editor>,
15362    ) {
15363        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15364        self.refresh_inline_diagnostics(false, window, cx);
15365    }
15366
15367    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15368        self.diagnostics_max_severity = severity;
15369        self.display_map.update(cx, |display_map, _| {
15370            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15371        });
15372    }
15373
15374    pub fn toggle_diagnostics(
15375        &mut self,
15376        _: &ToggleDiagnostics,
15377        window: &mut Window,
15378        cx: &mut Context<Editor>,
15379    ) {
15380        if !self.diagnostics_enabled() {
15381            return;
15382        }
15383
15384        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15385            EditorSettings::get_global(cx)
15386                .diagnostics_max_severity
15387                .filter(|severity| severity != &DiagnosticSeverity::Off)
15388                .unwrap_or(DiagnosticSeverity::Hint)
15389        } else {
15390            DiagnosticSeverity::Off
15391        };
15392        self.set_max_diagnostics_severity(new_severity, cx);
15393        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15394            self.active_diagnostics = ActiveDiagnostic::None;
15395            self.inline_diagnostics_update = Task::ready(());
15396            self.inline_diagnostics.clear();
15397        } else {
15398            self.refresh_inline_diagnostics(false, window, cx);
15399        }
15400
15401        cx.notify();
15402    }
15403
15404    pub fn toggle_minimap(
15405        &mut self,
15406        _: &ToggleMinimap,
15407        window: &mut Window,
15408        cx: &mut Context<Editor>,
15409    ) {
15410        if self.supports_minimap(cx) {
15411            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15412        }
15413    }
15414
15415    fn refresh_inline_diagnostics(
15416        &mut self,
15417        debounce: bool,
15418        window: &mut Window,
15419        cx: &mut Context<Self>,
15420    ) {
15421        let max_severity = ProjectSettings::get_global(cx)
15422            .diagnostics
15423            .inline
15424            .max_severity
15425            .unwrap_or(self.diagnostics_max_severity);
15426
15427        if self.mode.is_minimap()
15428            || !self.inline_diagnostics_enabled()
15429            || !self.show_inline_diagnostics
15430            || max_severity == DiagnosticSeverity::Off
15431        {
15432            self.inline_diagnostics_update = Task::ready(());
15433            self.inline_diagnostics.clear();
15434            return;
15435        }
15436
15437        let debounce_ms = ProjectSettings::get_global(cx)
15438            .diagnostics
15439            .inline
15440            .update_debounce_ms;
15441        let debounce = if debounce && debounce_ms > 0 {
15442            Some(Duration::from_millis(debounce_ms))
15443        } else {
15444            None
15445        };
15446        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15447            let editor = editor.upgrade().unwrap();
15448
15449            if let Some(debounce) = debounce {
15450                cx.background_executor().timer(debounce).await;
15451            }
15452            let Some(snapshot) = editor
15453                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15454                .ok()
15455            else {
15456                return;
15457            };
15458
15459            let new_inline_diagnostics = cx
15460                .background_spawn(async move {
15461                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15462                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15463                        let message = diagnostic_entry
15464                            .diagnostic
15465                            .message
15466                            .split_once('\n')
15467                            .map(|(line, _)| line)
15468                            .map(SharedString::new)
15469                            .unwrap_or_else(|| {
15470                                SharedString::from(diagnostic_entry.diagnostic.message)
15471                            });
15472                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15473                        let (Ok(i) | Err(i)) = inline_diagnostics
15474                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15475                        inline_diagnostics.insert(
15476                            i,
15477                            (
15478                                start_anchor,
15479                                InlineDiagnostic {
15480                                    message,
15481                                    group_id: diagnostic_entry.diagnostic.group_id,
15482                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15483                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15484                                    severity: diagnostic_entry.diagnostic.severity,
15485                                },
15486                            ),
15487                        );
15488                    }
15489                    inline_diagnostics
15490                })
15491                .await;
15492
15493            editor
15494                .update(cx, |editor, cx| {
15495                    editor.inline_diagnostics = new_inline_diagnostics;
15496                    cx.notify();
15497                })
15498                .ok();
15499        });
15500    }
15501
15502    pub fn set_selections_from_remote(
15503        &mut self,
15504        selections: Vec<Selection<Anchor>>,
15505        pending_selection: Option<Selection<Anchor>>,
15506        window: &mut Window,
15507        cx: &mut Context<Self>,
15508    ) {
15509        let old_cursor_position = self.selections.newest_anchor().head();
15510        self.selections.change_with(cx, |s| {
15511            s.select_anchors(selections);
15512            if let Some(pending_selection) = pending_selection {
15513                s.set_pending(pending_selection, SelectMode::Character);
15514            } else {
15515                s.clear_pending();
15516            }
15517        });
15518        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15519    }
15520
15521    fn push_to_selection_history(&mut self) {
15522        self.selection_history.push(SelectionHistoryEntry {
15523            selections: self.selections.disjoint_anchors(),
15524            select_next_state: self.select_next_state.clone(),
15525            select_prev_state: self.select_prev_state.clone(),
15526            add_selections_state: self.add_selections_state.clone(),
15527        });
15528    }
15529
15530    pub fn transact(
15531        &mut self,
15532        window: &mut Window,
15533        cx: &mut Context<Self>,
15534        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15535    ) -> Option<TransactionId> {
15536        self.start_transaction_at(Instant::now(), window, cx);
15537        update(self, window, cx);
15538        self.end_transaction_at(Instant::now(), cx)
15539    }
15540
15541    pub fn start_transaction_at(
15542        &mut self,
15543        now: Instant,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) {
15547        self.end_selection(window, cx);
15548        if let Some(tx_id) = self
15549            .buffer
15550            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15551        {
15552            self.selection_history
15553                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15554            cx.emit(EditorEvent::TransactionBegun {
15555                transaction_id: tx_id,
15556            })
15557        }
15558    }
15559
15560    pub fn end_transaction_at(
15561        &mut self,
15562        now: Instant,
15563        cx: &mut Context<Self>,
15564    ) -> Option<TransactionId> {
15565        if let Some(transaction_id) = self
15566            .buffer
15567            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15568        {
15569            if let Some((_, end_selections)) =
15570                self.selection_history.transaction_mut(transaction_id)
15571            {
15572                *end_selections = Some(self.selections.disjoint_anchors());
15573            } else {
15574                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15575            }
15576
15577            cx.emit(EditorEvent::Edited { transaction_id });
15578            Some(transaction_id)
15579        } else {
15580            None
15581        }
15582    }
15583
15584    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15585        if self.selection_mark_mode {
15586            self.change_selections(None, window, cx, |s| {
15587                s.move_with(|_, sel| {
15588                    sel.collapse_to(sel.head(), SelectionGoal::None);
15589                });
15590            })
15591        }
15592        self.selection_mark_mode = true;
15593        cx.notify();
15594    }
15595
15596    pub fn swap_selection_ends(
15597        &mut self,
15598        _: &actions::SwapSelectionEnds,
15599        window: &mut Window,
15600        cx: &mut Context<Self>,
15601    ) {
15602        self.change_selections(None, window, cx, |s| {
15603            s.move_with(|_, sel| {
15604                if sel.start != sel.end {
15605                    sel.reversed = !sel.reversed
15606                }
15607            });
15608        });
15609        self.request_autoscroll(Autoscroll::newest(), cx);
15610        cx.notify();
15611    }
15612
15613    pub fn toggle_fold(
15614        &mut self,
15615        _: &actions::ToggleFold,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) {
15619        if self.is_singleton(cx) {
15620            let selection = self.selections.newest::<Point>(cx);
15621
15622            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15623            let range = if selection.is_empty() {
15624                let point = selection.head().to_display_point(&display_map);
15625                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15626                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15627                    .to_point(&display_map);
15628                start..end
15629            } else {
15630                selection.range()
15631            };
15632            if display_map.folds_in_range(range).next().is_some() {
15633                self.unfold_lines(&Default::default(), window, cx)
15634            } else {
15635                self.fold(&Default::default(), window, cx)
15636            }
15637        } else {
15638            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15639            let buffer_ids: HashSet<_> = self
15640                .selections
15641                .disjoint_anchor_ranges()
15642                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15643                .collect();
15644
15645            let should_unfold = buffer_ids
15646                .iter()
15647                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15648
15649            for buffer_id in buffer_ids {
15650                if should_unfold {
15651                    self.unfold_buffer(buffer_id, cx);
15652                } else {
15653                    self.fold_buffer(buffer_id, cx);
15654                }
15655            }
15656        }
15657    }
15658
15659    pub fn toggle_fold_recursive(
15660        &mut self,
15661        _: &actions::ToggleFoldRecursive,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) {
15665        let selection = self.selections.newest::<Point>(cx);
15666
15667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15668        let range = if selection.is_empty() {
15669            let point = selection.head().to_display_point(&display_map);
15670            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15671            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15672                .to_point(&display_map);
15673            start..end
15674        } else {
15675            selection.range()
15676        };
15677        if display_map.folds_in_range(range).next().is_some() {
15678            self.unfold_recursive(&Default::default(), window, cx)
15679        } else {
15680            self.fold_recursive(&Default::default(), window, cx)
15681        }
15682    }
15683
15684    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15685        if self.is_singleton(cx) {
15686            let mut to_fold = Vec::new();
15687            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15688            let selections = self.selections.all_adjusted(cx);
15689
15690            for selection in selections {
15691                let range = selection.range().sorted();
15692                let buffer_start_row = range.start.row;
15693
15694                if range.start.row != range.end.row {
15695                    let mut found = false;
15696                    let mut row = range.start.row;
15697                    while row <= range.end.row {
15698                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15699                        {
15700                            found = true;
15701                            row = crease.range().end.row + 1;
15702                            to_fold.push(crease);
15703                        } else {
15704                            row += 1
15705                        }
15706                    }
15707                    if found {
15708                        continue;
15709                    }
15710                }
15711
15712                for row in (0..=range.start.row).rev() {
15713                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15714                        if crease.range().end.row >= buffer_start_row {
15715                            to_fold.push(crease);
15716                            if row <= range.start.row {
15717                                break;
15718                            }
15719                        }
15720                    }
15721                }
15722            }
15723
15724            self.fold_creases(to_fold, true, window, cx);
15725        } else {
15726            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15727            let buffer_ids = self
15728                .selections
15729                .disjoint_anchor_ranges()
15730                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15731                .collect::<HashSet<_>>();
15732            for buffer_id in buffer_ids {
15733                self.fold_buffer(buffer_id, cx);
15734            }
15735        }
15736    }
15737
15738    fn fold_at_level(
15739        &mut self,
15740        fold_at: &FoldAtLevel,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) {
15744        if !self.buffer.read(cx).is_singleton() {
15745            return;
15746        }
15747
15748        let fold_at_level = fold_at.0;
15749        let snapshot = self.buffer.read(cx).snapshot(cx);
15750        let mut to_fold = Vec::new();
15751        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15752
15753        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15754            while start_row < end_row {
15755                match self
15756                    .snapshot(window, cx)
15757                    .crease_for_buffer_row(MultiBufferRow(start_row))
15758                {
15759                    Some(crease) => {
15760                        let nested_start_row = crease.range().start.row + 1;
15761                        let nested_end_row = crease.range().end.row;
15762
15763                        if current_level < fold_at_level {
15764                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15765                        } else if current_level == fold_at_level {
15766                            to_fold.push(crease);
15767                        }
15768
15769                        start_row = nested_end_row + 1;
15770                    }
15771                    None => start_row += 1,
15772                }
15773            }
15774        }
15775
15776        self.fold_creases(to_fold, true, window, cx);
15777    }
15778
15779    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15780        if self.buffer.read(cx).is_singleton() {
15781            let mut fold_ranges = Vec::new();
15782            let snapshot = self.buffer.read(cx).snapshot(cx);
15783
15784            for row in 0..snapshot.max_row().0 {
15785                if let Some(foldable_range) = self
15786                    .snapshot(window, cx)
15787                    .crease_for_buffer_row(MultiBufferRow(row))
15788                {
15789                    fold_ranges.push(foldable_range);
15790                }
15791            }
15792
15793            self.fold_creases(fold_ranges, true, window, cx);
15794        } else {
15795            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15796                editor
15797                    .update_in(cx, |editor, _, cx| {
15798                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15799                            editor.fold_buffer(buffer_id, cx);
15800                        }
15801                    })
15802                    .ok();
15803            });
15804        }
15805    }
15806
15807    pub fn fold_function_bodies(
15808        &mut self,
15809        _: &actions::FoldFunctionBodies,
15810        window: &mut Window,
15811        cx: &mut Context<Self>,
15812    ) {
15813        let snapshot = self.buffer.read(cx).snapshot(cx);
15814
15815        let ranges = snapshot
15816            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15817            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15818            .collect::<Vec<_>>();
15819
15820        let creases = ranges
15821            .into_iter()
15822            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
15823            .collect();
15824
15825        self.fold_creases(creases, true, window, cx);
15826    }
15827
15828    pub fn fold_recursive(
15829        &mut self,
15830        _: &actions::FoldRecursive,
15831        window: &mut Window,
15832        cx: &mut Context<Self>,
15833    ) {
15834        let mut to_fold = Vec::new();
15835        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15836        let selections = self.selections.all_adjusted(cx);
15837
15838        for selection in selections {
15839            let range = selection.range().sorted();
15840            let buffer_start_row = range.start.row;
15841
15842            if range.start.row != range.end.row {
15843                let mut found = false;
15844                for row in range.start.row..=range.end.row {
15845                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15846                        found = true;
15847                        to_fold.push(crease);
15848                    }
15849                }
15850                if found {
15851                    continue;
15852                }
15853            }
15854
15855            for row in (0..=range.start.row).rev() {
15856                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15857                    if crease.range().end.row >= buffer_start_row {
15858                        to_fold.push(crease);
15859                    } else {
15860                        break;
15861                    }
15862                }
15863            }
15864        }
15865
15866        self.fold_creases(to_fold, true, window, cx);
15867    }
15868
15869    pub fn fold_at(
15870        &mut self,
15871        buffer_row: MultiBufferRow,
15872        window: &mut Window,
15873        cx: &mut Context<Self>,
15874    ) {
15875        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15876
15877        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
15878            let autoscroll = self
15879                .selections
15880                .all::<Point>(cx)
15881                .iter()
15882                .any(|selection| crease.range().overlaps(&selection.range()));
15883
15884            self.fold_creases(vec![crease], autoscroll, window, cx);
15885        }
15886    }
15887
15888    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
15889        if self.is_singleton(cx) {
15890            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15891            let buffer = &display_map.buffer_snapshot;
15892            let selections = self.selections.all::<Point>(cx);
15893            let ranges = selections
15894                .iter()
15895                .map(|s| {
15896                    let range = s.display_range(&display_map).sorted();
15897                    let mut start = range.start.to_point(&display_map);
15898                    let mut end = range.end.to_point(&display_map);
15899                    start.column = 0;
15900                    end.column = buffer.line_len(MultiBufferRow(end.row));
15901                    start..end
15902                })
15903                .collect::<Vec<_>>();
15904
15905            self.unfold_ranges(&ranges, true, true, cx);
15906        } else {
15907            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15908            let buffer_ids = self
15909                .selections
15910                .disjoint_anchor_ranges()
15911                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15912                .collect::<HashSet<_>>();
15913            for buffer_id in buffer_ids {
15914                self.unfold_buffer(buffer_id, cx);
15915            }
15916        }
15917    }
15918
15919    pub fn unfold_recursive(
15920        &mut self,
15921        _: &UnfoldRecursive,
15922        _window: &mut Window,
15923        cx: &mut Context<Self>,
15924    ) {
15925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15926        let selections = self.selections.all::<Point>(cx);
15927        let ranges = selections
15928            .iter()
15929            .map(|s| {
15930                let mut range = s.display_range(&display_map).sorted();
15931                *range.start.column_mut() = 0;
15932                *range.end.column_mut() = display_map.line_len(range.end.row());
15933                let start = range.start.to_point(&display_map);
15934                let end = range.end.to_point(&display_map);
15935                start..end
15936            })
15937            .collect::<Vec<_>>();
15938
15939        self.unfold_ranges(&ranges, true, true, cx);
15940    }
15941
15942    pub fn unfold_at(
15943        &mut self,
15944        buffer_row: MultiBufferRow,
15945        _window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15949
15950        let intersection_range = Point::new(buffer_row.0, 0)
15951            ..Point::new(
15952                buffer_row.0,
15953                display_map.buffer_snapshot.line_len(buffer_row),
15954            );
15955
15956        let autoscroll = self
15957            .selections
15958            .all::<Point>(cx)
15959            .iter()
15960            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
15961
15962        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
15963    }
15964
15965    pub fn unfold_all(
15966        &mut self,
15967        _: &actions::UnfoldAll,
15968        _window: &mut Window,
15969        cx: &mut Context<Self>,
15970    ) {
15971        if self.buffer.read(cx).is_singleton() {
15972            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15973            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
15974        } else {
15975            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
15976                editor
15977                    .update(cx, |editor, cx| {
15978                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15979                            editor.unfold_buffer(buffer_id, cx);
15980                        }
15981                    })
15982                    .ok();
15983            });
15984        }
15985    }
15986
15987    pub fn fold_selected_ranges(
15988        &mut self,
15989        _: &FoldSelectedRanges,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        let selections = self.selections.all_adjusted(cx);
15994        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15995        let ranges = selections
15996            .into_iter()
15997            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
15998            .collect::<Vec<_>>();
15999        self.fold_creases(ranges, true, window, cx);
16000    }
16001
16002    pub fn fold_ranges<T: ToOffset + Clone>(
16003        &mut self,
16004        ranges: Vec<Range<T>>,
16005        auto_scroll: bool,
16006        window: &mut Window,
16007        cx: &mut Context<Self>,
16008    ) {
16009        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16010        let ranges = ranges
16011            .into_iter()
16012            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16013            .collect::<Vec<_>>();
16014        self.fold_creases(ranges, auto_scroll, window, cx);
16015    }
16016
16017    pub fn fold_creases<T: ToOffset + Clone>(
16018        &mut self,
16019        creases: Vec<Crease<T>>,
16020        auto_scroll: bool,
16021        _window: &mut Window,
16022        cx: &mut Context<Self>,
16023    ) {
16024        if creases.is_empty() {
16025            return;
16026        }
16027
16028        let mut buffers_affected = HashSet::default();
16029        let multi_buffer = self.buffer().read(cx);
16030        for crease in &creases {
16031            if let Some((_, buffer, _)) =
16032                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16033            {
16034                buffers_affected.insert(buffer.read(cx).remote_id());
16035            };
16036        }
16037
16038        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16039
16040        if auto_scroll {
16041            self.request_autoscroll(Autoscroll::fit(), cx);
16042        }
16043
16044        cx.notify();
16045
16046        self.scrollbar_marker_state.dirty = true;
16047        self.folds_did_change(cx);
16048    }
16049
16050    /// Removes any folds whose ranges intersect any of the given ranges.
16051    pub fn unfold_ranges<T: ToOffset + Clone>(
16052        &mut self,
16053        ranges: &[Range<T>],
16054        inclusive: bool,
16055        auto_scroll: bool,
16056        cx: &mut Context<Self>,
16057    ) {
16058        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16059            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16060        });
16061        self.folds_did_change(cx);
16062    }
16063
16064    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16065        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16066            return;
16067        }
16068        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16069        self.display_map.update(cx, |display_map, cx| {
16070            display_map.fold_buffers([buffer_id], cx)
16071        });
16072        cx.emit(EditorEvent::BufferFoldToggled {
16073            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16074            folded: true,
16075        });
16076        cx.notify();
16077    }
16078
16079    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16080        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16081            return;
16082        }
16083        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16084        self.display_map.update(cx, |display_map, cx| {
16085            display_map.unfold_buffers([buffer_id], cx);
16086        });
16087        cx.emit(EditorEvent::BufferFoldToggled {
16088            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16089            folded: false,
16090        });
16091        cx.notify();
16092    }
16093
16094    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16095        self.display_map.read(cx).is_buffer_folded(buffer)
16096    }
16097
16098    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16099        self.display_map.read(cx).folded_buffers()
16100    }
16101
16102    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16103        self.display_map.update(cx, |display_map, cx| {
16104            display_map.disable_header_for_buffer(buffer_id, cx);
16105        });
16106        cx.notify();
16107    }
16108
16109    /// Removes any folds with the given ranges.
16110    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16111        &mut self,
16112        ranges: &[Range<T>],
16113        type_id: TypeId,
16114        auto_scroll: bool,
16115        cx: &mut Context<Self>,
16116    ) {
16117        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16118            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16119        });
16120        self.folds_did_change(cx);
16121    }
16122
16123    fn remove_folds_with<T: ToOffset + Clone>(
16124        &mut self,
16125        ranges: &[Range<T>],
16126        auto_scroll: bool,
16127        cx: &mut Context<Self>,
16128        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16129    ) {
16130        if ranges.is_empty() {
16131            return;
16132        }
16133
16134        let mut buffers_affected = HashSet::default();
16135        let multi_buffer = self.buffer().read(cx);
16136        for range in ranges {
16137            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16138                buffers_affected.insert(buffer.read(cx).remote_id());
16139            };
16140        }
16141
16142        self.display_map.update(cx, update);
16143
16144        if auto_scroll {
16145            self.request_autoscroll(Autoscroll::fit(), cx);
16146        }
16147
16148        cx.notify();
16149        self.scrollbar_marker_state.dirty = true;
16150        self.active_indent_guides_state.dirty = true;
16151    }
16152
16153    pub fn update_fold_widths(
16154        &mut self,
16155        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16156        cx: &mut Context<Self>,
16157    ) -> bool {
16158        self.display_map
16159            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16160    }
16161
16162    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16163        self.display_map.read(cx).fold_placeholder.clone()
16164    }
16165
16166    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16167        self.buffer.update(cx, |buffer, cx| {
16168            buffer.set_all_diff_hunks_expanded(cx);
16169        });
16170    }
16171
16172    pub fn expand_all_diff_hunks(
16173        &mut self,
16174        _: &ExpandAllDiffHunks,
16175        _window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) {
16178        self.buffer.update(cx, |buffer, cx| {
16179            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16180        });
16181    }
16182
16183    pub fn toggle_selected_diff_hunks(
16184        &mut self,
16185        _: &ToggleSelectedDiffHunks,
16186        _window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16190        self.toggle_diff_hunks_in_ranges(ranges, cx);
16191    }
16192
16193    pub fn diff_hunks_in_ranges<'a>(
16194        &'a self,
16195        ranges: &'a [Range<Anchor>],
16196        buffer: &'a MultiBufferSnapshot,
16197    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16198        ranges.iter().flat_map(move |range| {
16199            let end_excerpt_id = range.end.excerpt_id;
16200            let range = range.to_point(buffer);
16201            let mut peek_end = range.end;
16202            if range.end.row < buffer.max_row().0 {
16203                peek_end = Point::new(range.end.row + 1, 0);
16204            }
16205            buffer
16206                .diff_hunks_in_range(range.start..peek_end)
16207                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16208        })
16209    }
16210
16211    pub fn has_stageable_diff_hunks_in_ranges(
16212        &self,
16213        ranges: &[Range<Anchor>],
16214        snapshot: &MultiBufferSnapshot,
16215    ) -> bool {
16216        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16217        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16218    }
16219
16220    pub fn toggle_staged_selected_diff_hunks(
16221        &mut self,
16222        _: &::git::ToggleStaged,
16223        _: &mut Window,
16224        cx: &mut Context<Self>,
16225    ) {
16226        let snapshot = self.buffer.read(cx).snapshot(cx);
16227        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16228        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16229        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16230    }
16231
16232    pub fn set_render_diff_hunk_controls(
16233        &mut self,
16234        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16235        cx: &mut Context<Self>,
16236    ) {
16237        self.render_diff_hunk_controls = render_diff_hunk_controls;
16238        cx.notify();
16239    }
16240
16241    pub fn stage_and_next(
16242        &mut self,
16243        _: &::git::StageAndNext,
16244        window: &mut Window,
16245        cx: &mut Context<Self>,
16246    ) {
16247        self.do_stage_or_unstage_and_next(true, window, cx);
16248    }
16249
16250    pub fn unstage_and_next(
16251        &mut self,
16252        _: &::git::UnstageAndNext,
16253        window: &mut Window,
16254        cx: &mut Context<Self>,
16255    ) {
16256        self.do_stage_or_unstage_and_next(false, window, cx);
16257    }
16258
16259    pub fn stage_or_unstage_diff_hunks(
16260        &mut self,
16261        stage: bool,
16262        ranges: Vec<Range<Anchor>>,
16263        cx: &mut Context<Self>,
16264    ) {
16265        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16266        cx.spawn(async move |this, cx| {
16267            task.await?;
16268            this.update(cx, |this, cx| {
16269                let snapshot = this.buffer.read(cx).snapshot(cx);
16270                let chunk_by = this
16271                    .diff_hunks_in_ranges(&ranges, &snapshot)
16272                    .chunk_by(|hunk| hunk.buffer_id);
16273                for (buffer_id, hunks) in &chunk_by {
16274                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16275                }
16276            })
16277        })
16278        .detach_and_log_err(cx);
16279    }
16280
16281    fn save_buffers_for_ranges_if_needed(
16282        &mut self,
16283        ranges: &[Range<Anchor>],
16284        cx: &mut Context<Editor>,
16285    ) -> Task<Result<()>> {
16286        let multibuffer = self.buffer.read(cx);
16287        let snapshot = multibuffer.read(cx);
16288        let buffer_ids: HashSet<_> = ranges
16289            .iter()
16290            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16291            .collect();
16292        drop(snapshot);
16293
16294        let mut buffers = HashSet::default();
16295        for buffer_id in buffer_ids {
16296            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16297                let buffer = buffer_entity.read(cx);
16298                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16299                {
16300                    buffers.insert(buffer_entity);
16301                }
16302            }
16303        }
16304
16305        if let Some(project) = &self.project {
16306            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16307        } else {
16308            Task::ready(Ok(()))
16309        }
16310    }
16311
16312    fn do_stage_or_unstage_and_next(
16313        &mut self,
16314        stage: bool,
16315        window: &mut Window,
16316        cx: &mut Context<Self>,
16317    ) {
16318        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16319
16320        if ranges.iter().any(|range| range.start != range.end) {
16321            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16322            return;
16323        }
16324
16325        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16326        let snapshot = self.snapshot(window, cx);
16327        let position = self.selections.newest::<Point>(cx).head();
16328        let mut row = snapshot
16329            .buffer_snapshot
16330            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16331            .find(|hunk| hunk.row_range.start.0 > position.row)
16332            .map(|hunk| hunk.row_range.start);
16333
16334        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16335        // Outside of the project diff editor, wrap around to the beginning.
16336        if !all_diff_hunks_expanded {
16337            row = row.or_else(|| {
16338                snapshot
16339                    .buffer_snapshot
16340                    .diff_hunks_in_range(Point::zero()..position)
16341                    .find(|hunk| hunk.row_range.end.0 < position.row)
16342                    .map(|hunk| hunk.row_range.start)
16343            });
16344        }
16345
16346        if let Some(row) = row {
16347            let destination = Point::new(row.0, 0);
16348            let autoscroll = Autoscroll::center();
16349
16350            self.unfold_ranges(&[destination..destination], false, false, cx);
16351            self.change_selections(Some(autoscroll), window, cx, |s| {
16352                s.select_ranges([destination..destination]);
16353            });
16354        }
16355    }
16356
16357    fn do_stage_or_unstage(
16358        &self,
16359        stage: bool,
16360        buffer_id: BufferId,
16361        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16362        cx: &mut App,
16363    ) -> Option<()> {
16364        let project = self.project.as_ref()?;
16365        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16366        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16367        let buffer_snapshot = buffer.read(cx).snapshot();
16368        let file_exists = buffer_snapshot
16369            .file()
16370            .is_some_and(|file| file.disk_state().exists());
16371        diff.update(cx, |diff, cx| {
16372            diff.stage_or_unstage_hunks(
16373                stage,
16374                &hunks
16375                    .map(|hunk| buffer_diff::DiffHunk {
16376                        buffer_range: hunk.buffer_range,
16377                        diff_base_byte_range: hunk.diff_base_byte_range,
16378                        secondary_status: hunk.secondary_status,
16379                        range: Point::zero()..Point::zero(), // unused
16380                    })
16381                    .collect::<Vec<_>>(),
16382                &buffer_snapshot,
16383                file_exists,
16384                cx,
16385            )
16386        });
16387        None
16388    }
16389
16390    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16391        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16392        self.buffer
16393            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16394    }
16395
16396    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16397        self.buffer.update(cx, |buffer, cx| {
16398            let ranges = vec![Anchor::min()..Anchor::max()];
16399            if !buffer.all_diff_hunks_expanded()
16400                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16401            {
16402                buffer.collapse_diff_hunks(ranges, cx);
16403                true
16404            } else {
16405                false
16406            }
16407        })
16408    }
16409
16410    fn toggle_diff_hunks_in_ranges(
16411        &mut self,
16412        ranges: Vec<Range<Anchor>>,
16413        cx: &mut Context<Editor>,
16414    ) {
16415        self.buffer.update(cx, |buffer, cx| {
16416            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16417            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16418        })
16419    }
16420
16421    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16422        self.buffer.update(cx, |buffer, cx| {
16423            let snapshot = buffer.snapshot(cx);
16424            let excerpt_id = range.end.excerpt_id;
16425            let point_range = range.to_point(&snapshot);
16426            let expand = !buffer.single_hunk_is_expanded(range, cx);
16427            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16428        })
16429    }
16430
16431    pub(crate) fn apply_all_diff_hunks(
16432        &mut self,
16433        _: &ApplyAllDiffHunks,
16434        window: &mut Window,
16435        cx: &mut Context<Self>,
16436    ) {
16437        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16438
16439        let buffers = self.buffer.read(cx).all_buffers();
16440        for branch_buffer in buffers {
16441            branch_buffer.update(cx, |branch_buffer, cx| {
16442                branch_buffer.merge_into_base(Vec::new(), cx);
16443            });
16444        }
16445
16446        if let Some(project) = self.project.clone() {
16447            self.save(true, project, window, cx).detach_and_log_err(cx);
16448        }
16449    }
16450
16451    pub(crate) fn apply_selected_diff_hunks(
16452        &mut self,
16453        _: &ApplyDiffHunk,
16454        window: &mut Window,
16455        cx: &mut Context<Self>,
16456    ) {
16457        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16458        let snapshot = self.snapshot(window, cx);
16459        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16460        let mut ranges_by_buffer = HashMap::default();
16461        self.transact(window, cx, |editor, _window, cx| {
16462            for hunk in hunks {
16463                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16464                    ranges_by_buffer
16465                        .entry(buffer.clone())
16466                        .or_insert_with(Vec::new)
16467                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16468                }
16469            }
16470
16471            for (buffer, ranges) in ranges_by_buffer {
16472                buffer.update(cx, |buffer, cx| {
16473                    buffer.merge_into_base(ranges, cx);
16474                });
16475            }
16476        });
16477
16478        if let Some(project) = self.project.clone() {
16479            self.save(true, project, window, cx).detach_and_log_err(cx);
16480        }
16481    }
16482
16483    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16484        if hovered != self.gutter_hovered {
16485            self.gutter_hovered = hovered;
16486            cx.notify();
16487        }
16488    }
16489
16490    pub fn insert_blocks(
16491        &mut self,
16492        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16493        autoscroll: Option<Autoscroll>,
16494        cx: &mut Context<Self>,
16495    ) -> Vec<CustomBlockId> {
16496        let blocks = self
16497            .display_map
16498            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16499        if let Some(autoscroll) = autoscroll {
16500            self.request_autoscroll(autoscroll, cx);
16501        }
16502        cx.notify();
16503        blocks
16504    }
16505
16506    pub fn resize_blocks(
16507        &mut self,
16508        heights: HashMap<CustomBlockId, u32>,
16509        autoscroll: Option<Autoscroll>,
16510        cx: &mut Context<Self>,
16511    ) {
16512        self.display_map
16513            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16514        if let Some(autoscroll) = autoscroll {
16515            self.request_autoscroll(autoscroll, cx);
16516        }
16517        cx.notify();
16518    }
16519
16520    pub fn replace_blocks(
16521        &mut self,
16522        renderers: HashMap<CustomBlockId, RenderBlock>,
16523        autoscroll: Option<Autoscroll>,
16524        cx: &mut Context<Self>,
16525    ) {
16526        self.display_map
16527            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16528        if let Some(autoscroll) = autoscroll {
16529            self.request_autoscroll(autoscroll, cx);
16530        }
16531        cx.notify();
16532    }
16533
16534    pub fn remove_blocks(
16535        &mut self,
16536        block_ids: HashSet<CustomBlockId>,
16537        autoscroll: Option<Autoscroll>,
16538        cx: &mut Context<Self>,
16539    ) {
16540        self.display_map.update(cx, |display_map, cx| {
16541            display_map.remove_blocks(block_ids, cx)
16542        });
16543        if let Some(autoscroll) = autoscroll {
16544            self.request_autoscroll(autoscroll, cx);
16545        }
16546        cx.notify();
16547    }
16548
16549    pub fn row_for_block(
16550        &self,
16551        block_id: CustomBlockId,
16552        cx: &mut Context<Self>,
16553    ) -> Option<DisplayRow> {
16554        self.display_map
16555            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16556    }
16557
16558    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16559        self.focused_block = Some(focused_block);
16560    }
16561
16562    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16563        self.focused_block.take()
16564    }
16565
16566    pub fn insert_creases(
16567        &mut self,
16568        creases: impl IntoIterator<Item = Crease<Anchor>>,
16569        cx: &mut Context<Self>,
16570    ) -> Vec<CreaseId> {
16571        self.display_map
16572            .update(cx, |map, cx| map.insert_creases(creases, cx))
16573    }
16574
16575    pub fn remove_creases(
16576        &mut self,
16577        ids: impl IntoIterator<Item = CreaseId>,
16578        cx: &mut Context<Self>,
16579    ) -> Vec<(CreaseId, Range<Anchor>)> {
16580        self.display_map
16581            .update(cx, |map, cx| map.remove_creases(ids, cx))
16582    }
16583
16584    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16585        self.display_map
16586            .update(cx, |map, cx| map.snapshot(cx))
16587            .longest_row()
16588    }
16589
16590    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16591        self.display_map
16592            .update(cx, |map, cx| map.snapshot(cx))
16593            .max_point()
16594    }
16595
16596    pub fn text(&self, cx: &App) -> String {
16597        self.buffer.read(cx).read(cx).text()
16598    }
16599
16600    pub fn is_empty(&self, cx: &App) -> bool {
16601        self.buffer.read(cx).read(cx).is_empty()
16602    }
16603
16604    pub fn text_option(&self, cx: &App) -> Option<String> {
16605        let text = self.text(cx);
16606        let text = text.trim();
16607
16608        if text.is_empty() {
16609            return None;
16610        }
16611
16612        Some(text.to_string())
16613    }
16614
16615    pub fn set_text(
16616        &mut self,
16617        text: impl Into<Arc<str>>,
16618        window: &mut Window,
16619        cx: &mut Context<Self>,
16620    ) {
16621        self.transact(window, cx, |this, _, cx| {
16622            this.buffer
16623                .read(cx)
16624                .as_singleton()
16625                .expect("you can only call set_text on editors for singleton buffers")
16626                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16627        });
16628    }
16629
16630    pub fn display_text(&self, cx: &mut App) -> String {
16631        self.display_map
16632            .update(cx, |map, cx| map.snapshot(cx))
16633            .text()
16634    }
16635
16636    fn create_minimap(
16637        &self,
16638        minimap_settings: MinimapSettings,
16639        window: &mut Window,
16640        cx: &mut Context<Self>,
16641    ) -> Option<Entity<Self>> {
16642        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16643            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16644    }
16645
16646    fn initialize_new_minimap(
16647        &self,
16648        minimap_settings: MinimapSettings,
16649        window: &mut Window,
16650        cx: &mut Context<Self>,
16651    ) -> Entity<Self> {
16652        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16653
16654        let mut minimap = Editor::new_internal(
16655            EditorMode::Minimap {
16656                parent: cx.weak_entity(),
16657            },
16658            self.buffer.clone(),
16659            self.project.clone(),
16660            Some(self.display_map.clone()),
16661            window,
16662            cx,
16663        );
16664        minimap.scroll_manager.clone_state(&self.scroll_manager);
16665        minimap.set_text_style_refinement(TextStyleRefinement {
16666            font_size: Some(MINIMAP_FONT_SIZE),
16667            font_weight: Some(MINIMAP_FONT_WEIGHT),
16668            ..Default::default()
16669        });
16670        minimap.update_minimap_configuration(minimap_settings, cx);
16671        cx.new(|_| minimap)
16672    }
16673
16674    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16675        let current_line_highlight = minimap_settings
16676            .current_line_highlight
16677            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16678        self.set_current_line_highlight(Some(current_line_highlight));
16679    }
16680
16681    pub fn minimap(&self) -> Option<&Entity<Self>> {
16682        self.minimap
16683            .as_ref()
16684            .filter(|_| self.minimap_visibility.visible())
16685    }
16686
16687    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16688        let mut wrap_guides = smallvec::smallvec![];
16689
16690        if self.show_wrap_guides == Some(false) {
16691            return wrap_guides;
16692        }
16693
16694        let settings = self.buffer.read(cx).language_settings(cx);
16695        if settings.show_wrap_guides {
16696            match self.soft_wrap_mode(cx) {
16697                SoftWrap::Column(soft_wrap) => {
16698                    wrap_guides.push((soft_wrap as usize, true));
16699                }
16700                SoftWrap::Bounded(soft_wrap) => {
16701                    wrap_guides.push((soft_wrap as usize, true));
16702                }
16703                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16704            }
16705            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16706        }
16707
16708        wrap_guides
16709    }
16710
16711    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16712        let settings = self.buffer.read(cx).language_settings(cx);
16713        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16714        match mode {
16715            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16716                SoftWrap::None
16717            }
16718            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16719            language_settings::SoftWrap::PreferredLineLength => {
16720                SoftWrap::Column(settings.preferred_line_length)
16721            }
16722            language_settings::SoftWrap::Bounded => {
16723                SoftWrap::Bounded(settings.preferred_line_length)
16724            }
16725        }
16726    }
16727
16728    pub fn set_soft_wrap_mode(
16729        &mut self,
16730        mode: language_settings::SoftWrap,
16731
16732        cx: &mut Context<Self>,
16733    ) {
16734        self.soft_wrap_mode_override = Some(mode);
16735        cx.notify();
16736    }
16737
16738    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16739        self.hard_wrap = hard_wrap;
16740        cx.notify();
16741    }
16742
16743    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16744        self.text_style_refinement = Some(style);
16745    }
16746
16747    /// called by the Element so we know what style we were most recently rendered with.
16748    pub(crate) fn set_style(
16749        &mut self,
16750        style: EditorStyle,
16751        window: &mut Window,
16752        cx: &mut Context<Self>,
16753    ) {
16754        // We intentionally do not inform the display map about the minimap style
16755        // so that wrapping is not recalculated and stays consistent for the editor
16756        // and its linked minimap.
16757        if !self.mode.is_minimap() {
16758            let rem_size = window.rem_size();
16759            self.display_map.update(cx, |map, cx| {
16760                map.set_font(
16761                    style.text.font(),
16762                    style.text.font_size.to_pixels(rem_size),
16763                    cx,
16764                )
16765            });
16766        }
16767        self.style = Some(style);
16768    }
16769
16770    pub fn style(&self) -> Option<&EditorStyle> {
16771        self.style.as_ref()
16772    }
16773
16774    // Called by the element. This method is not designed to be called outside of the editor
16775    // element's layout code because it does not notify when rewrapping is computed synchronously.
16776    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16777        self.display_map
16778            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16779    }
16780
16781    pub fn set_soft_wrap(&mut self) {
16782        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16783    }
16784
16785    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16786        if self.soft_wrap_mode_override.is_some() {
16787            self.soft_wrap_mode_override.take();
16788        } else {
16789            let soft_wrap = match self.soft_wrap_mode(cx) {
16790                SoftWrap::GitDiff => return,
16791                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16792                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16793                    language_settings::SoftWrap::None
16794                }
16795            };
16796            self.soft_wrap_mode_override = Some(soft_wrap);
16797        }
16798        cx.notify();
16799    }
16800
16801    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16802        let Some(workspace) = self.workspace() else {
16803            return;
16804        };
16805        let fs = workspace.read(cx).app_state().fs.clone();
16806        let current_show = TabBarSettings::get_global(cx).show;
16807        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16808            setting.show = Some(!current_show);
16809        });
16810    }
16811
16812    pub fn toggle_indent_guides(
16813        &mut self,
16814        _: &ToggleIndentGuides,
16815        _: &mut Window,
16816        cx: &mut Context<Self>,
16817    ) {
16818        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16819            self.buffer
16820                .read(cx)
16821                .language_settings(cx)
16822                .indent_guides
16823                .enabled
16824        });
16825        self.show_indent_guides = Some(!currently_enabled);
16826        cx.notify();
16827    }
16828
16829    fn should_show_indent_guides(&self) -> Option<bool> {
16830        self.show_indent_guides
16831    }
16832
16833    pub fn toggle_line_numbers(
16834        &mut self,
16835        _: &ToggleLineNumbers,
16836        _: &mut Window,
16837        cx: &mut Context<Self>,
16838    ) {
16839        let mut editor_settings = EditorSettings::get_global(cx).clone();
16840        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
16841        EditorSettings::override_global(editor_settings, cx);
16842    }
16843
16844    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
16845        if let Some(show_line_numbers) = self.show_line_numbers {
16846            return show_line_numbers;
16847        }
16848        EditorSettings::get_global(cx).gutter.line_numbers
16849    }
16850
16851    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
16852        self.use_relative_line_numbers
16853            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
16854    }
16855
16856    pub fn toggle_relative_line_numbers(
16857        &mut self,
16858        _: &ToggleRelativeLineNumbers,
16859        _: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let is_relative = self.should_use_relative_line_numbers(cx);
16863        self.set_relative_line_number(Some(!is_relative), cx)
16864    }
16865
16866    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
16867        self.use_relative_line_numbers = is_relative;
16868        cx.notify();
16869    }
16870
16871    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
16872        self.show_gutter = show_gutter;
16873        cx.notify();
16874    }
16875
16876    pub fn set_show_scrollbars(&mut self, show_scrollbars: bool, cx: &mut Context<Self>) {
16877        self.show_scrollbars = show_scrollbars;
16878        cx.notify();
16879    }
16880
16881    pub fn set_minimap_visibility(
16882        &mut self,
16883        minimap_visibility: MinimapVisibility,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) {
16887        if self.minimap_visibility != minimap_visibility {
16888            if minimap_visibility.visible() && self.minimap.is_none() {
16889                let minimap_settings = EditorSettings::get_global(cx).minimap;
16890                self.minimap =
16891                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
16892            }
16893            self.minimap_visibility = minimap_visibility;
16894            cx.notify();
16895        }
16896    }
16897
16898    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
16899        self.set_show_scrollbars(false, cx);
16900        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
16901    }
16902
16903    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
16904        self.show_line_numbers = Some(show_line_numbers);
16905        cx.notify();
16906    }
16907
16908    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
16909        self.disable_expand_excerpt_buttons = true;
16910        cx.notify();
16911    }
16912
16913    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
16914        self.show_git_diff_gutter = Some(show_git_diff_gutter);
16915        cx.notify();
16916    }
16917
16918    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
16919        self.show_code_actions = Some(show_code_actions);
16920        cx.notify();
16921    }
16922
16923    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
16924        self.show_runnables = Some(show_runnables);
16925        cx.notify();
16926    }
16927
16928    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
16929        self.show_breakpoints = Some(show_breakpoints);
16930        cx.notify();
16931    }
16932
16933    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
16934        if self.display_map.read(cx).masked != masked {
16935            self.display_map.update(cx, |map, _| map.masked = masked);
16936        }
16937        cx.notify()
16938    }
16939
16940    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
16941        self.show_wrap_guides = Some(show_wrap_guides);
16942        cx.notify();
16943    }
16944
16945    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
16946        self.show_indent_guides = Some(show_indent_guides);
16947        cx.notify();
16948    }
16949
16950    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
16951        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
16952            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
16953                if let Some(dir) = file.abs_path(cx).parent() {
16954                    return Some(dir.to_owned());
16955                }
16956            }
16957
16958            if let Some(project_path) = buffer.read(cx).project_path(cx) {
16959                return Some(project_path.path.to_path_buf());
16960            }
16961        }
16962
16963        None
16964    }
16965
16966    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
16967        self.active_excerpt(cx)?
16968            .1
16969            .read(cx)
16970            .file()
16971            .and_then(|f| f.as_local())
16972    }
16973
16974    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16975        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16976            let buffer = buffer.read(cx);
16977            if let Some(project_path) = buffer.project_path(cx) {
16978                let project = self.project.as_ref()?.read(cx);
16979                project.absolute_path(&project_path, cx)
16980            } else {
16981                buffer
16982                    .file()
16983                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
16984            }
16985        })
16986    }
16987
16988    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
16989        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
16990            let project_path = buffer.read(cx).project_path(cx)?;
16991            let project = self.project.as_ref()?.read(cx);
16992            let entry = project.entry_for_path(&project_path, cx)?;
16993            let path = entry.path.to_path_buf();
16994            Some(path)
16995        })
16996    }
16997
16998    pub fn reveal_in_finder(
16999        &mut self,
17000        _: &RevealInFileManager,
17001        _window: &mut Window,
17002        cx: &mut Context<Self>,
17003    ) {
17004        if let Some(target) = self.target_file(cx) {
17005            cx.reveal_path(&target.abs_path(cx));
17006        }
17007    }
17008
17009    pub fn copy_path(
17010        &mut self,
17011        _: &zed_actions::workspace::CopyPath,
17012        _window: &mut Window,
17013        cx: &mut Context<Self>,
17014    ) {
17015        if let Some(path) = self.target_file_abs_path(cx) {
17016            if let Some(path) = path.to_str() {
17017                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17018            }
17019        }
17020    }
17021
17022    pub fn copy_relative_path(
17023        &mut self,
17024        _: &zed_actions::workspace::CopyRelativePath,
17025        _window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        if let Some(path) = self.target_file_path(cx) {
17029            if let Some(path) = path.to_str() {
17030                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17031            }
17032        }
17033    }
17034
17035    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17036        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17037            buffer.read(cx).project_path(cx)
17038        } else {
17039            None
17040        }
17041    }
17042
17043    // Returns true if the editor handled a go-to-line request
17044    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17045        maybe!({
17046            let breakpoint_store = self.breakpoint_store.as_ref()?;
17047
17048            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17049            else {
17050                self.clear_row_highlights::<ActiveDebugLine>();
17051                return None;
17052            };
17053
17054            let position = active_stack_frame.position;
17055            let buffer_id = position.buffer_id?;
17056            let snapshot = self
17057                .project
17058                .as_ref()?
17059                .read(cx)
17060                .buffer_for_id(buffer_id, cx)?
17061                .read(cx)
17062                .snapshot();
17063
17064            let mut handled = false;
17065            for (id, ExcerptRange { context, .. }) in
17066                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17067            {
17068                if context.start.cmp(&position, &snapshot).is_ge()
17069                    || context.end.cmp(&position, &snapshot).is_lt()
17070                {
17071                    continue;
17072                }
17073                let snapshot = self.buffer.read(cx).snapshot(cx);
17074                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17075
17076                handled = true;
17077                self.clear_row_highlights::<ActiveDebugLine>();
17078
17079                self.go_to_line::<ActiveDebugLine>(
17080                    multibuffer_anchor,
17081                    Some(cx.theme().colors().editor_debugger_active_line_background),
17082                    window,
17083                    cx,
17084                );
17085
17086                cx.notify();
17087            }
17088
17089            handled.then_some(())
17090        })
17091        .is_some()
17092    }
17093
17094    pub fn copy_file_name_without_extension(
17095        &mut self,
17096        _: &CopyFileNameWithoutExtension,
17097        _: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) {
17100        if let Some(file) = self.target_file(cx) {
17101            if let Some(file_stem) = file.path().file_stem() {
17102                if let Some(name) = file_stem.to_str() {
17103                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17104                }
17105            }
17106        }
17107    }
17108
17109    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17110        if let Some(file) = self.target_file(cx) {
17111            if let Some(file_name) = file.path().file_name() {
17112                if let Some(name) = file_name.to_str() {
17113                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17114                }
17115            }
17116        }
17117    }
17118
17119    pub fn toggle_git_blame(
17120        &mut self,
17121        _: &::git::Blame,
17122        window: &mut Window,
17123        cx: &mut Context<Self>,
17124    ) {
17125        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17126
17127        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17128            self.start_git_blame(true, window, cx);
17129        }
17130
17131        cx.notify();
17132    }
17133
17134    pub fn toggle_git_blame_inline(
17135        &mut self,
17136        _: &ToggleGitBlameInline,
17137        window: &mut Window,
17138        cx: &mut Context<Self>,
17139    ) {
17140        self.toggle_git_blame_inline_internal(true, window, cx);
17141        cx.notify();
17142    }
17143
17144    pub fn open_git_blame_commit(
17145        &mut self,
17146        _: &OpenGitBlameCommit,
17147        window: &mut Window,
17148        cx: &mut Context<Self>,
17149    ) {
17150        self.open_git_blame_commit_internal(window, cx);
17151    }
17152
17153    fn open_git_blame_commit_internal(
17154        &mut self,
17155        window: &mut Window,
17156        cx: &mut Context<Self>,
17157    ) -> Option<()> {
17158        let blame = self.blame.as_ref()?;
17159        let snapshot = self.snapshot(window, cx);
17160        let cursor = self.selections.newest::<Point>(cx).head();
17161        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17162        let blame_entry = blame
17163            .update(cx, |blame, cx| {
17164                blame
17165                    .blame_for_rows(
17166                        &[RowInfo {
17167                            buffer_id: Some(buffer.remote_id()),
17168                            buffer_row: Some(point.row),
17169                            ..Default::default()
17170                        }],
17171                        cx,
17172                    )
17173                    .next()
17174            })
17175            .flatten()?;
17176        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17177        let repo = blame.read(cx).repository(cx)?;
17178        let workspace = self.workspace()?.downgrade();
17179        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17180        None
17181    }
17182
17183    pub fn git_blame_inline_enabled(&self) -> bool {
17184        self.git_blame_inline_enabled
17185    }
17186
17187    pub fn toggle_selection_menu(
17188        &mut self,
17189        _: &ToggleSelectionMenu,
17190        _: &mut Window,
17191        cx: &mut Context<Self>,
17192    ) {
17193        self.show_selection_menu = self
17194            .show_selection_menu
17195            .map(|show_selections_menu| !show_selections_menu)
17196            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17197
17198        cx.notify();
17199    }
17200
17201    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17202        self.show_selection_menu
17203            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17204    }
17205
17206    fn start_git_blame(
17207        &mut self,
17208        user_triggered: bool,
17209        window: &mut Window,
17210        cx: &mut Context<Self>,
17211    ) {
17212        if let Some(project) = self.project.as_ref() {
17213            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17214                return;
17215            };
17216
17217            if buffer.read(cx).file().is_none() {
17218                return;
17219            }
17220
17221            let focused = self.focus_handle(cx).contains_focused(window, cx);
17222
17223            let project = project.clone();
17224            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17225            self.blame_subscription =
17226                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17227            self.blame = Some(blame);
17228        }
17229    }
17230
17231    fn toggle_git_blame_inline_internal(
17232        &mut self,
17233        user_triggered: bool,
17234        window: &mut Window,
17235        cx: &mut Context<Self>,
17236    ) {
17237        if self.git_blame_inline_enabled {
17238            self.git_blame_inline_enabled = false;
17239            self.show_git_blame_inline = false;
17240            self.show_git_blame_inline_delay_task.take();
17241        } else {
17242            self.git_blame_inline_enabled = true;
17243            self.start_git_blame_inline(user_triggered, window, cx);
17244        }
17245
17246        cx.notify();
17247    }
17248
17249    fn start_git_blame_inline(
17250        &mut self,
17251        user_triggered: bool,
17252        window: &mut Window,
17253        cx: &mut Context<Self>,
17254    ) {
17255        self.start_git_blame(user_triggered, window, cx);
17256
17257        if ProjectSettings::get_global(cx)
17258            .git
17259            .inline_blame_delay()
17260            .is_some()
17261        {
17262            self.start_inline_blame_timer(window, cx);
17263        } else {
17264            self.show_git_blame_inline = true
17265        }
17266    }
17267
17268    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17269        self.blame.as_ref()
17270    }
17271
17272    pub fn show_git_blame_gutter(&self) -> bool {
17273        self.show_git_blame_gutter
17274    }
17275
17276    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17277        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17278    }
17279
17280    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17281        self.show_git_blame_inline
17282            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17283            && !self.newest_selection_head_on_empty_line(cx)
17284            && self.has_blame_entries(cx)
17285    }
17286
17287    fn has_blame_entries(&self, cx: &App) -> bool {
17288        self.blame()
17289            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17290    }
17291
17292    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17293        let cursor_anchor = self.selections.newest_anchor().head();
17294
17295        let snapshot = self.buffer.read(cx).snapshot(cx);
17296        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17297
17298        snapshot.line_len(buffer_row) == 0
17299    }
17300
17301    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17302        let buffer_and_selection = maybe!({
17303            let selection = self.selections.newest::<Point>(cx);
17304            let selection_range = selection.range();
17305
17306            let multi_buffer = self.buffer().read(cx);
17307            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17308            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17309
17310            let (buffer, range, _) = if selection.reversed {
17311                buffer_ranges.first()
17312            } else {
17313                buffer_ranges.last()
17314            }?;
17315
17316            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17317                ..text::ToPoint::to_point(&range.end, &buffer).row;
17318            Some((
17319                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17320                selection,
17321            ))
17322        });
17323
17324        let Some((buffer, selection)) = buffer_and_selection else {
17325            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17326        };
17327
17328        let Some(project) = self.project.as_ref() else {
17329            return Task::ready(Err(anyhow!("editor does not have project")));
17330        };
17331
17332        project.update(cx, |project, cx| {
17333            project.get_permalink_to_line(&buffer, selection, cx)
17334        })
17335    }
17336
17337    pub fn copy_permalink_to_line(
17338        &mut self,
17339        _: &CopyPermalinkToLine,
17340        window: &mut Window,
17341        cx: &mut Context<Self>,
17342    ) {
17343        let permalink_task = self.get_permalink_to_line(cx);
17344        let workspace = self.workspace();
17345
17346        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17347            Ok(permalink) => {
17348                cx.update(|_, cx| {
17349                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17350                })
17351                .ok();
17352            }
17353            Err(err) => {
17354                let message = format!("Failed to copy permalink: {err}");
17355
17356                anyhow::Result::<()>::Err(err).log_err();
17357
17358                if let Some(workspace) = workspace {
17359                    workspace
17360                        .update_in(cx, |workspace, _, cx| {
17361                            struct CopyPermalinkToLine;
17362
17363                            workspace.show_toast(
17364                                Toast::new(
17365                                    NotificationId::unique::<CopyPermalinkToLine>(),
17366                                    message,
17367                                ),
17368                                cx,
17369                            )
17370                        })
17371                        .ok();
17372                }
17373            }
17374        })
17375        .detach();
17376    }
17377
17378    pub fn copy_file_location(
17379        &mut self,
17380        _: &CopyFileLocation,
17381        _: &mut Window,
17382        cx: &mut Context<Self>,
17383    ) {
17384        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17385        if let Some(file) = self.target_file(cx) {
17386            if let Some(path) = file.path().to_str() {
17387                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17388            }
17389        }
17390    }
17391
17392    pub fn open_permalink_to_line(
17393        &mut self,
17394        _: &OpenPermalinkToLine,
17395        window: &mut Window,
17396        cx: &mut Context<Self>,
17397    ) {
17398        let permalink_task = self.get_permalink_to_line(cx);
17399        let workspace = self.workspace();
17400
17401        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17402            Ok(permalink) => {
17403                cx.update(|_, cx| {
17404                    cx.open_url(permalink.as_ref());
17405                })
17406                .ok();
17407            }
17408            Err(err) => {
17409                let message = format!("Failed to open permalink: {err}");
17410
17411                anyhow::Result::<()>::Err(err).log_err();
17412
17413                if let Some(workspace) = workspace {
17414                    workspace
17415                        .update(cx, |workspace, cx| {
17416                            struct OpenPermalinkToLine;
17417
17418                            workspace.show_toast(
17419                                Toast::new(
17420                                    NotificationId::unique::<OpenPermalinkToLine>(),
17421                                    message,
17422                                ),
17423                                cx,
17424                            )
17425                        })
17426                        .ok();
17427                }
17428            }
17429        })
17430        .detach();
17431    }
17432
17433    pub fn insert_uuid_v4(
17434        &mut self,
17435        _: &InsertUuidV4,
17436        window: &mut Window,
17437        cx: &mut Context<Self>,
17438    ) {
17439        self.insert_uuid(UuidVersion::V4, window, cx);
17440    }
17441
17442    pub fn insert_uuid_v7(
17443        &mut self,
17444        _: &InsertUuidV7,
17445        window: &mut Window,
17446        cx: &mut Context<Self>,
17447    ) {
17448        self.insert_uuid(UuidVersion::V7, window, cx);
17449    }
17450
17451    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17452        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17453        self.transact(window, cx, |this, window, cx| {
17454            let edits = this
17455                .selections
17456                .all::<Point>(cx)
17457                .into_iter()
17458                .map(|selection| {
17459                    let uuid = match version {
17460                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17461                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17462                    };
17463
17464                    (selection.range(), uuid.to_string())
17465                });
17466            this.edit(edits, cx);
17467            this.refresh_inline_completion(true, false, window, cx);
17468        });
17469    }
17470
17471    pub fn open_selections_in_multibuffer(
17472        &mut self,
17473        _: &OpenSelectionsInMultibuffer,
17474        window: &mut Window,
17475        cx: &mut Context<Self>,
17476    ) {
17477        let multibuffer = self.buffer.read(cx);
17478
17479        let Some(buffer) = multibuffer.as_singleton() else {
17480            return;
17481        };
17482
17483        let Some(workspace) = self.workspace() else {
17484            return;
17485        };
17486
17487        let locations = self
17488            .selections
17489            .disjoint_anchors()
17490            .iter()
17491            .map(|range| Location {
17492                buffer: buffer.clone(),
17493                range: range.start.text_anchor..range.end.text_anchor,
17494            })
17495            .collect::<Vec<_>>();
17496
17497        let title = multibuffer.title(cx).to_string();
17498
17499        cx.spawn_in(window, async move |_, cx| {
17500            workspace.update_in(cx, |workspace, window, cx| {
17501                Self::open_locations_in_multibuffer(
17502                    workspace,
17503                    locations,
17504                    format!("Selections for '{title}'"),
17505                    false,
17506                    MultibufferSelectionMode::All,
17507                    window,
17508                    cx,
17509                );
17510            })
17511        })
17512        .detach();
17513    }
17514
17515    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17516    /// last highlight added will be used.
17517    ///
17518    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17519    pub fn highlight_rows<T: 'static>(
17520        &mut self,
17521        range: Range<Anchor>,
17522        color: Hsla,
17523        options: RowHighlightOptions,
17524        cx: &mut Context<Self>,
17525    ) {
17526        let snapshot = self.buffer().read(cx).snapshot(cx);
17527        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17528        let ix = row_highlights.binary_search_by(|highlight| {
17529            Ordering::Equal
17530                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17531                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17532        });
17533
17534        if let Err(mut ix) = ix {
17535            let index = post_inc(&mut self.highlight_order);
17536
17537            // If this range intersects with the preceding highlight, then merge it with
17538            // the preceding highlight. Otherwise insert a new highlight.
17539            let mut merged = false;
17540            if ix > 0 {
17541                let prev_highlight = &mut row_highlights[ix - 1];
17542                if prev_highlight
17543                    .range
17544                    .end
17545                    .cmp(&range.start, &snapshot)
17546                    .is_ge()
17547                {
17548                    ix -= 1;
17549                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17550                        prev_highlight.range.end = range.end;
17551                    }
17552                    merged = true;
17553                    prev_highlight.index = index;
17554                    prev_highlight.color = color;
17555                    prev_highlight.options = options;
17556                }
17557            }
17558
17559            if !merged {
17560                row_highlights.insert(
17561                    ix,
17562                    RowHighlight {
17563                        range: range.clone(),
17564                        index,
17565                        color,
17566                        options,
17567                        type_id: TypeId::of::<T>(),
17568                    },
17569                );
17570            }
17571
17572            // If any of the following highlights intersect with this one, merge them.
17573            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17574                let highlight = &row_highlights[ix];
17575                if next_highlight
17576                    .range
17577                    .start
17578                    .cmp(&highlight.range.end, &snapshot)
17579                    .is_le()
17580                {
17581                    if next_highlight
17582                        .range
17583                        .end
17584                        .cmp(&highlight.range.end, &snapshot)
17585                        .is_gt()
17586                    {
17587                        row_highlights[ix].range.end = next_highlight.range.end;
17588                    }
17589                    row_highlights.remove(ix + 1);
17590                } else {
17591                    break;
17592                }
17593            }
17594        }
17595    }
17596
17597    /// Remove any highlighted row ranges of the given type that intersect the
17598    /// given ranges.
17599    pub fn remove_highlighted_rows<T: 'static>(
17600        &mut self,
17601        ranges_to_remove: Vec<Range<Anchor>>,
17602        cx: &mut Context<Self>,
17603    ) {
17604        let snapshot = self.buffer().read(cx).snapshot(cx);
17605        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17606        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17607        row_highlights.retain(|highlight| {
17608            while let Some(range_to_remove) = ranges_to_remove.peek() {
17609                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17610                    Ordering::Less | Ordering::Equal => {
17611                        ranges_to_remove.next();
17612                    }
17613                    Ordering::Greater => {
17614                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17615                            Ordering::Less | Ordering::Equal => {
17616                                return false;
17617                            }
17618                            Ordering::Greater => break,
17619                        }
17620                    }
17621                }
17622            }
17623
17624            true
17625        })
17626    }
17627
17628    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17629    pub fn clear_row_highlights<T: 'static>(&mut self) {
17630        self.highlighted_rows.remove(&TypeId::of::<T>());
17631    }
17632
17633    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17634    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17635        self.highlighted_rows
17636            .get(&TypeId::of::<T>())
17637            .map_or(&[] as &[_], |vec| vec.as_slice())
17638            .iter()
17639            .map(|highlight| (highlight.range.clone(), highlight.color))
17640    }
17641
17642    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17643    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17644    /// Allows to ignore certain kinds of highlights.
17645    pub fn highlighted_display_rows(
17646        &self,
17647        window: &mut Window,
17648        cx: &mut App,
17649    ) -> BTreeMap<DisplayRow, LineHighlight> {
17650        let snapshot = self.snapshot(window, cx);
17651        let mut used_highlight_orders = HashMap::default();
17652        self.highlighted_rows
17653            .iter()
17654            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17655            .fold(
17656                BTreeMap::<DisplayRow, LineHighlight>::new(),
17657                |mut unique_rows, highlight| {
17658                    let start = highlight.range.start.to_display_point(&snapshot);
17659                    let end = highlight.range.end.to_display_point(&snapshot);
17660                    let start_row = start.row().0;
17661                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17662                        && end.column() == 0
17663                    {
17664                        end.row().0.saturating_sub(1)
17665                    } else {
17666                        end.row().0
17667                    };
17668                    for row in start_row..=end_row {
17669                        let used_index =
17670                            used_highlight_orders.entry(row).or_insert(highlight.index);
17671                        if highlight.index >= *used_index {
17672                            *used_index = highlight.index;
17673                            unique_rows.insert(
17674                                DisplayRow(row),
17675                                LineHighlight {
17676                                    include_gutter: highlight.options.include_gutter,
17677                                    border: None,
17678                                    background: highlight.color.into(),
17679                                    type_id: Some(highlight.type_id),
17680                                },
17681                            );
17682                        }
17683                    }
17684                    unique_rows
17685                },
17686            )
17687    }
17688
17689    pub fn highlighted_display_row_for_autoscroll(
17690        &self,
17691        snapshot: &DisplaySnapshot,
17692    ) -> Option<DisplayRow> {
17693        self.highlighted_rows
17694            .values()
17695            .flat_map(|highlighted_rows| highlighted_rows.iter())
17696            .filter_map(|highlight| {
17697                if highlight.options.autoscroll {
17698                    Some(highlight.range.start.to_display_point(snapshot).row())
17699                } else {
17700                    None
17701                }
17702            })
17703            .min()
17704    }
17705
17706    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17707        self.highlight_background::<SearchWithinRange>(
17708            ranges,
17709            |colors| colors.editor_document_highlight_read_background,
17710            cx,
17711        )
17712    }
17713
17714    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17715        self.breadcrumb_header = Some(new_header);
17716    }
17717
17718    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17719        self.clear_background_highlights::<SearchWithinRange>(cx);
17720    }
17721
17722    pub fn highlight_background<T: 'static>(
17723        &mut self,
17724        ranges: &[Range<Anchor>],
17725        color_fetcher: fn(&ThemeColors) -> Hsla,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.background_highlights
17729            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17730        self.scrollbar_marker_state.dirty = true;
17731        cx.notify();
17732    }
17733
17734    pub fn clear_background_highlights<T: 'static>(
17735        &mut self,
17736        cx: &mut Context<Self>,
17737    ) -> Option<BackgroundHighlight> {
17738        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17739        if !text_highlights.1.is_empty() {
17740            self.scrollbar_marker_state.dirty = true;
17741            cx.notify();
17742        }
17743        Some(text_highlights)
17744    }
17745
17746    pub fn highlight_gutter<T: 'static>(
17747        &mut self,
17748        ranges: &[Range<Anchor>],
17749        color_fetcher: fn(&App) -> Hsla,
17750        cx: &mut Context<Self>,
17751    ) {
17752        self.gutter_highlights
17753            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17754        cx.notify();
17755    }
17756
17757    pub fn clear_gutter_highlights<T: 'static>(
17758        &mut self,
17759        cx: &mut Context<Self>,
17760    ) -> Option<GutterHighlight> {
17761        cx.notify();
17762        self.gutter_highlights.remove(&TypeId::of::<T>())
17763    }
17764
17765    #[cfg(feature = "test-support")]
17766    pub fn all_text_background_highlights(
17767        &self,
17768        window: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17771        let snapshot = self.snapshot(window, cx);
17772        let buffer = &snapshot.buffer_snapshot;
17773        let start = buffer.anchor_before(0);
17774        let end = buffer.anchor_after(buffer.len());
17775        let theme = cx.theme().colors();
17776        self.background_highlights_in_range(start..end, &snapshot, theme)
17777    }
17778
17779    #[cfg(feature = "test-support")]
17780    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17781        let snapshot = self.buffer().read(cx).snapshot(cx);
17782
17783        let highlights = self
17784            .background_highlights
17785            .get(&TypeId::of::<items::BufferSearchHighlights>());
17786
17787        if let Some((_color, ranges)) = highlights {
17788            ranges
17789                .iter()
17790                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
17791                .collect_vec()
17792        } else {
17793            vec![]
17794        }
17795    }
17796
17797    fn document_highlights_for_position<'a>(
17798        &'a self,
17799        position: Anchor,
17800        buffer: &'a MultiBufferSnapshot,
17801    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
17802        let read_highlights = self
17803            .background_highlights
17804            .get(&TypeId::of::<DocumentHighlightRead>())
17805            .map(|h| &h.1);
17806        let write_highlights = self
17807            .background_highlights
17808            .get(&TypeId::of::<DocumentHighlightWrite>())
17809            .map(|h| &h.1);
17810        let left_position = position.bias_left(buffer);
17811        let right_position = position.bias_right(buffer);
17812        read_highlights
17813            .into_iter()
17814            .chain(write_highlights)
17815            .flat_map(move |ranges| {
17816                let start_ix = match ranges.binary_search_by(|probe| {
17817                    let cmp = probe.end.cmp(&left_position, buffer);
17818                    if cmp.is_ge() {
17819                        Ordering::Greater
17820                    } else {
17821                        Ordering::Less
17822                    }
17823                }) {
17824                    Ok(i) | Err(i) => i,
17825                };
17826
17827                ranges[start_ix..]
17828                    .iter()
17829                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
17830            })
17831    }
17832
17833    pub fn has_background_highlights<T: 'static>(&self) -> bool {
17834        self.background_highlights
17835            .get(&TypeId::of::<T>())
17836            .map_or(false, |(_, highlights)| !highlights.is_empty())
17837    }
17838
17839    pub fn background_highlights_in_range(
17840        &self,
17841        search_range: Range<Anchor>,
17842        display_snapshot: &DisplaySnapshot,
17843        theme: &ThemeColors,
17844    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17845        let mut results = Vec::new();
17846        for (color_fetcher, ranges) in self.background_highlights.values() {
17847            let color = color_fetcher(theme);
17848            let start_ix = match ranges.binary_search_by(|probe| {
17849                let cmp = probe
17850                    .end
17851                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17852                if cmp.is_gt() {
17853                    Ordering::Greater
17854                } else {
17855                    Ordering::Less
17856                }
17857            }) {
17858                Ok(i) | Err(i) => i,
17859            };
17860            for range in &ranges[start_ix..] {
17861                if range
17862                    .start
17863                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17864                    .is_ge()
17865                {
17866                    break;
17867                }
17868
17869                let start = range.start.to_display_point(display_snapshot);
17870                let end = range.end.to_display_point(display_snapshot);
17871                results.push((start..end, color))
17872            }
17873        }
17874        results
17875    }
17876
17877    pub fn background_highlight_row_ranges<T: 'static>(
17878        &self,
17879        search_range: Range<Anchor>,
17880        display_snapshot: &DisplaySnapshot,
17881        count: usize,
17882    ) -> Vec<RangeInclusive<DisplayPoint>> {
17883        let mut results = Vec::new();
17884        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
17885            return vec![];
17886        };
17887
17888        let start_ix = match ranges.binary_search_by(|probe| {
17889            let cmp = probe
17890                .end
17891                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17892            if cmp.is_gt() {
17893                Ordering::Greater
17894            } else {
17895                Ordering::Less
17896            }
17897        }) {
17898            Ok(i) | Err(i) => i,
17899        };
17900        let mut push_region = |start: Option<Point>, end: Option<Point>| {
17901            if let (Some(start_display), Some(end_display)) = (start, end) {
17902                results.push(
17903                    start_display.to_display_point(display_snapshot)
17904                        ..=end_display.to_display_point(display_snapshot),
17905                );
17906            }
17907        };
17908        let mut start_row: Option<Point> = None;
17909        let mut end_row: Option<Point> = None;
17910        if ranges.len() > count {
17911            return Vec::new();
17912        }
17913        for range in &ranges[start_ix..] {
17914            if range
17915                .start
17916                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17917                .is_ge()
17918            {
17919                break;
17920            }
17921            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
17922            if let Some(current_row) = &end_row {
17923                if end.row == current_row.row {
17924                    continue;
17925                }
17926            }
17927            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
17928            if start_row.is_none() {
17929                assert_eq!(end_row, None);
17930                start_row = Some(start);
17931                end_row = Some(end);
17932                continue;
17933            }
17934            if let Some(current_end) = end_row.as_mut() {
17935                if start.row > current_end.row + 1 {
17936                    push_region(start_row, end_row);
17937                    start_row = Some(start);
17938                    end_row = Some(end);
17939                } else {
17940                    // Merge two hunks.
17941                    *current_end = end;
17942                }
17943            } else {
17944                unreachable!();
17945            }
17946        }
17947        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
17948        push_region(start_row, end_row);
17949        results
17950    }
17951
17952    pub fn gutter_highlights_in_range(
17953        &self,
17954        search_range: Range<Anchor>,
17955        display_snapshot: &DisplaySnapshot,
17956        cx: &App,
17957    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17958        let mut results = Vec::new();
17959        for (color_fetcher, ranges) in self.gutter_highlights.values() {
17960            let color = color_fetcher(cx);
17961            let start_ix = match ranges.binary_search_by(|probe| {
17962                let cmp = probe
17963                    .end
17964                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
17965                if cmp.is_gt() {
17966                    Ordering::Greater
17967                } else {
17968                    Ordering::Less
17969                }
17970            }) {
17971                Ok(i) | Err(i) => i,
17972            };
17973            for range in &ranges[start_ix..] {
17974                if range
17975                    .start
17976                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
17977                    .is_ge()
17978                {
17979                    break;
17980                }
17981
17982                let start = range.start.to_display_point(display_snapshot);
17983                let end = range.end.to_display_point(display_snapshot);
17984                results.push((start..end, color))
17985            }
17986        }
17987        results
17988    }
17989
17990    /// Get the text ranges corresponding to the redaction query
17991    pub fn redacted_ranges(
17992        &self,
17993        search_range: Range<Anchor>,
17994        display_snapshot: &DisplaySnapshot,
17995        cx: &App,
17996    ) -> Vec<Range<DisplayPoint>> {
17997        display_snapshot
17998            .buffer_snapshot
17999            .redacted_ranges(search_range, |file| {
18000                if let Some(file) = file {
18001                    file.is_private()
18002                        && EditorSettings::get(
18003                            Some(SettingsLocation {
18004                                worktree_id: file.worktree_id(cx),
18005                                path: file.path().as_ref(),
18006                            }),
18007                            cx,
18008                        )
18009                        .redact_private_values
18010                } else {
18011                    false
18012                }
18013            })
18014            .map(|range| {
18015                range.start.to_display_point(display_snapshot)
18016                    ..range.end.to_display_point(display_snapshot)
18017            })
18018            .collect()
18019    }
18020
18021    pub fn highlight_text<T: 'static>(
18022        &mut self,
18023        ranges: Vec<Range<Anchor>>,
18024        style: HighlightStyle,
18025        cx: &mut Context<Self>,
18026    ) {
18027        self.display_map.update(cx, |map, _| {
18028            map.highlight_text(TypeId::of::<T>(), ranges, style)
18029        });
18030        cx.notify();
18031    }
18032
18033    pub(crate) fn highlight_inlays<T: 'static>(
18034        &mut self,
18035        highlights: Vec<InlayHighlight>,
18036        style: HighlightStyle,
18037        cx: &mut Context<Self>,
18038    ) {
18039        self.display_map.update(cx, |map, _| {
18040            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18041        });
18042        cx.notify();
18043    }
18044
18045    pub fn text_highlights<'a, T: 'static>(
18046        &'a self,
18047        cx: &'a App,
18048    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18049        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18050    }
18051
18052    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18053        let cleared = self
18054            .display_map
18055            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18056        if cleared {
18057            cx.notify();
18058        }
18059    }
18060
18061    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18062        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18063            && self.focus_handle.is_focused(window)
18064    }
18065
18066    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18067        self.show_cursor_when_unfocused = is_enabled;
18068        cx.notify();
18069    }
18070
18071    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18072        cx.notify();
18073    }
18074
18075    fn on_debug_session_event(
18076        &mut self,
18077        _session: Entity<Session>,
18078        event: &SessionEvent,
18079        cx: &mut Context<Self>,
18080    ) {
18081        match event {
18082            SessionEvent::InvalidateInlineValue => {
18083                self.refresh_inline_values(cx);
18084            }
18085            _ => {}
18086        }
18087    }
18088
18089    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18090        let Some(project) = self.project.clone() else {
18091            return;
18092        };
18093
18094        if !self.inline_value_cache.enabled {
18095            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18096            self.splice_inlays(&inlays, Vec::new(), cx);
18097            return;
18098        }
18099
18100        let current_execution_position = self
18101            .highlighted_rows
18102            .get(&TypeId::of::<ActiveDebugLine>())
18103            .and_then(|lines| lines.last().map(|line| line.range.start));
18104
18105        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18106            let inline_values = editor
18107                .update(cx, |editor, cx| {
18108                    let Some(current_execution_position) = current_execution_position else {
18109                        return Some(Task::ready(Ok(Vec::new())));
18110                    };
18111
18112                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18113                        let snapshot = buffer.snapshot(cx);
18114
18115                        let excerpt = snapshot.excerpt_containing(
18116                            current_execution_position..current_execution_position,
18117                        )?;
18118
18119                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18120                    })?;
18121
18122                    let range =
18123                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18124
18125                    project.inline_values(buffer, range, cx)
18126                })
18127                .ok()
18128                .flatten()?
18129                .await
18130                .context("refreshing debugger inlays")
18131                .log_err()?;
18132
18133            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18134
18135            for (buffer_id, inline_value) in inline_values
18136                .into_iter()
18137                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18138            {
18139                buffer_inline_values
18140                    .entry(buffer_id)
18141                    .or_default()
18142                    .push(inline_value);
18143            }
18144
18145            editor
18146                .update(cx, |editor, cx| {
18147                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18148                    let mut new_inlays = Vec::default();
18149
18150                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18151                        let buffer_id = buffer_snapshot.remote_id();
18152                        buffer_inline_values
18153                            .get(&buffer_id)
18154                            .into_iter()
18155                            .flatten()
18156                            .for_each(|hint| {
18157                                let inlay = Inlay::debugger_hint(
18158                                    post_inc(&mut editor.next_inlay_id),
18159                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18160                                    hint.text(),
18161                                );
18162
18163                                new_inlays.push(inlay);
18164                            });
18165                    }
18166
18167                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18168                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18169
18170                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18171                })
18172                .ok()?;
18173            Some(())
18174        });
18175    }
18176
18177    fn on_buffer_event(
18178        &mut self,
18179        multibuffer: &Entity<MultiBuffer>,
18180        event: &multi_buffer::Event,
18181        window: &mut Window,
18182        cx: &mut Context<Self>,
18183    ) {
18184        match event {
18185            multi_buffer::Event::Edited {
18186                singleton_buffer_edited,
18187                edited_buffer: buffer_edited,
18188            } => {
18189                self.scrollbar_marker_state.dirty = true;
18190                self.active_indent_guides_state.dirty = true;
18191                self.refresh_active_diagnostics(cx);
18192                self.refresh_code_actions(window, cx);
18193                self.refresh_selected_text_highlights(true, window, cx);
18194                refresh_matching_bracket_highlights(self, window, cx);
18195                if self.has_active_inline_completion() {
18196                    self.update_visible_inline_completion(window, cx);
18197                }
18198                if let Some(buffer) = buffer_edited {
18199                    let buffer_id = buffer.read(cx).remote_id();
18200                    if !self.registered_buffers.contains_key(&buffer_id) {
18201                        if let Some(project) = self.project.as_ref() {
18202                            project.update(cx, |project, cx| {
18203                                self.registered_buffers.insert(
18204                                    buffer_id,
18205                                    project.register_buffer_with_language_servers(&buffer, cx),
18206                                );
18207                            })
18208                        }
18209                    }
18210                }
18211                cx.emit(EditorEvent::BufferEdited);
18212                cx.emit(SearchEvent::MatchesInvalidated);
18213                if *singleton_buffer_edited {
18214                    if let Some(project) = &self.project {
18215                        #[allow(clippy::mutable_key_type)]
18216                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18217                            multibuffer
18218                                .all_buffers()
18219                                .into_iter()
18220                                .filter_map(|buffer| {
18221                                    buffer.update(cx, |buffer, cx| {
18222                                        let language = buffer.language()?;
18223                                        let should_discard = project.update(cx, |project, cx| {
18224                                            project.is_local()
18225                                                && !project.has_language_servers_for(buffer, cx)
18226                                        });
18227                                        should_discard.not().then_some(language.clone())
18228                                    })
18229                                })
18230                                .collect::<HashSet<_>>()
18231                        });
18232                        if !languages_affected.is_empty() {
18233                            self.refresh_inlay_hints(
18234                                InlayHintRefreshReason::BufferEdited(languages_affected),
18235                                cx,
18236                            );
18237                        }
18238                    }
18239                }
18240
18241                let Some(project) = &self.project else { return };
18242                let (telemetry, is_via_ssh) = {
18243                    let project = project.read(cx);
18244                    let telemetry = project.client().telemetry().clone();
18245                    let is_via_ssh = project.is_via_ssh();
18246                    (telemetry, is_via_ssh)
18247                };
18248                refresh_linked_ranges(self, window, cx);
18249                telemetry.log_edit_event("editor", is_via_ssh);
18250            }
18251            multi_buffer::Event::ExcerptsAdded {
18252                buffer,
18253                predecessor,
18254                excerpts,
18255            } => {
18256                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18257                let buffer_id = buffer.read(cx).remote_id();
18258                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18259                    if let Some(project) = &self.project {
18260                        update_uncommitted_diff_for_buffer(
18261                            cx.entity(),
18262                            project,
18263                            [buffer.clone()],
18264                            self.buffer.clone(),
18265                            cx,
18266                        )
18267                        .detach();
18268                    }
18269                }
18270                cx.emit(EditorEvent::ExcerptsAdded {
18271                    buffer: buffer.clone(),
18272                    predecessor: *predecessor,
18273                    excerpts: excerpts.clone(),
18274                });
18275                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18276            }
18277            multi_buffer::Event::ExcerptsRemoved {
18278                ids,
18279                removed_buffer_ids,
18280            } => {
18281                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18282                let buffer = self.buffer.read(cx);
18283                self.registered_buffers
18284                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18285                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18286                cx.emit(EditorEvent::ExcerptsRemoved {
18287                    ids: ids.clone(),
18288                    removed_buffer_ids: removed_buffer_ids.clone(),
18289                })
18290            }
18291            multi_buffer::Event::ExcerptsEdited {
18292                excerpt_ids,
18293                buffer_ids,
18294            } => {
18295                self.display_map.update(cx, |map, cx| {
18296                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18297                });
18298                cx.emit(EditorEvent::ExcerptsEdited {
18299                    ids: excerpt_ids.clone(),
18300                })
18301            }
18302            multi_buffer::Event::ExcerptsExpanded { ids } => {
18303                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18304                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18305            }
18306            multi_buffer::Event::Reparsed(buffer_id) => {
18307                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18308                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18309
18310                cx.emit(EditorEvent::Reparsed(*buffer_id));
18311            }
18312            multi_buffer::Event::DiffHunksToggled => {
18313                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18314            }
18315            multi_buffer::Event::LanguageChanged(buffer_id) => {
18316                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18317                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18318                cx.emit(EditorEvent::Reparsed(*buffer_id));
18319                cx.notify();
18320            }
18321            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18322            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18323            multi_buffer::Event::FileHandleChanged
18324            | multi_buffer::Event::Reloaded
18325            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18326            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18327            multi_buffer::Event::DiagnosticsUpdated => {
18328                self.refresh_active_diagnostics(cx);
18329                self.refresh_inline_diagnostics(true, window, cx);
18330                self.scrollbar_marker_state.dirty = true;
18331                cx.notify();
18332            }
18333            _ => {}
18334        };
18335    }
18336
18337    pub fn start_temporary_diff_override(&mut self) {
18338        self.load_diff_task.take();
18339        self.temporary_diff_override = true;
18340    }
18341
18342    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18343        self.temporary_diff_override = false;
18344        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18345        self.buffer.update(cx, |buffer, cx| {
18346            buffer.set_all_diff_hunks_collapsed(cx);
18347        });
18348
18349        if let Some(project) = self.project.clone() {
18350            self.load_diff_task = Some(
18351                update_uncommitted_diff_for_buffer(
18352                    cx.entity(),
18353                    &project,
18354                    self.buffer.read(cx).all_buffers(),
18355                    self.buffer.clone(),
18356                    cx,
18357                )
18358                .shared(),
18359            );
18360        }
18361    }
18362
18363    fn on_display_map_changed(
18364        &mut self,
18365        _: Entity<DisplayMap>,
18366        _: &mut Window,
18367        cx: &mut Context<Self>,
18368    ) {
18369        cx.notify();
18370    }
18371
18372    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18373        let new_severity = if self.diagnostics_enabled() {
18374            EditorSettings::get_global(cx)
18375                .diagnostics_max_severity
18376                .unwrap_or(DiagnosticSeverity::Hint)
18377        } else {
18378            DiagnosticSeverity::Off
18379        };
18380        self.set_max_diagnostics_severity(new_severity, cx);
18381        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18382        self.update_edit_prediction_settings(cx);
18383        self.refresh_inline_completion(true, false, window, cx);
18384        self.refresh_inlay_hints(
18385            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18386                self.selections.newest_anchor().head(),
18387                &self.buffer.read(cx).snapshot(cx),
18388                cx,
18389            )),
18390            cx,
18391        );
18392
18393        let old_cursor_shape = self.cursor_shape;
18394
18395        {
18396            let editor_settings = EditorSettings::get_global(cx);
18397            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18398            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18399            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18400            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18401        }
18402
18403        if old_cursor_shape != self.cursor_shape {
18404            cx.emit(EditorEvent::CursorShapeChanged);
18405        }
18406
18407        let project_settings = ProjectSettings::get_global(cx);
18408        self.serialize_dirty_buffers =
18409            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18410
18411        if self.mode.is_full() {
18412            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18413            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18414            if self.show_inline_diagnostics != show_inline_diagnostics {
18415                self.show_inline_diagnostics = show_inline_diagnostics;
18416                self.refresh_inline_diagnostics(false, window, cx);
18417            }
18418
18419            if self.git_blame_inline_enabled != inline_blame_enabled {
18420                self.toggle_git_blame_inline_internal(false, window, cx);
18421            }
18422
18423            let minimap_settings = EditorSettings::get_global(cx).minimap;
18424            if self.minimap_visibility.visible() != minimap_settings.minimap_enabled() {
18425                self.set_minimap_visibility(
18426                    self.minimap_visibility.toggle_visibility(),
18427                    window,
18428                    cx,
18429                );
18430            } else if let Some(minimap_entity) = self.minimap.as_ref() {
18431                minimap_entity.update(cx, |minimap_editor, cx| {
18432                    minimap_editor.update_minimap_configuration(minimap_settings, cx)
18433                })
18434            }
18435        }
18436
18437        cx.notify();
18438    }
18439
18440    pub fn set_searchable(&mut self, searchable: bool) {
18441        self.searchable = searchable;
18442    }
18443
18444    pub fn searchable(&self) -> bool {
18445        self.searchable
18446    }
18447
18448    fn open_proposed_changes_editor(
18449        &mut self,
18450        _: &OpenProposedChangesEditor,
18451        window: &mut Window,
18452        cx: &mut Context<Self>,
18453    ) {
18454        let Some(workspace) = self.workspace() else {
18455            cx.propagate();
18456            return;
18457        };
18458
18459        let selections = self.selections.all::<usize>(cx);
18460        let multi_buffer = self.buffer.read(cx);
18461        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18462        let mut new_selections_by_buffer = HashMap::default();
18463        for selection in selections {
18464            for (buffer, range, _) in
18465                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18466            {
18467                let mut range = range.to_point(buffer);
18468                range.start.column = 0;
18469                range.end.column = buffer.line_len(range.end.row);
18470                new_selections_by_buffer
18471                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18472                    .or_insert(Vec::new())
18473                    .push(range)
18474            }
18475        }
18476
18477        let proposed_changes_buffers = new_selections_by_buffer
18478            .into_iter()
18479            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18480            .collect::<Vec<_>>();
18481        let proposed_changes_editor = cx.new(|cx| {
18482            ProposedChangesEditor::new(
18483                "Proposed changes",
18484                proposed_changes_buffers,
18485                self.project.clone(),
18486                window,
18487                cx,
18488            )
18489        });
18490
18491        window.defer(cx, move |window, cx| {
18492            workspace.update(cx, |workspace, cx| {
18493                workspace.active_pane().update(cx, |pane, cx| {
18494                    pane.add_item(
18495                        Box::new(proposed_changes_editor),
18496                        true,
18497                        true,
18498                        None,
18499                        window,
18500                        cx,
18501                    );
18502                });
18503            });
18504        });
18505    }
18506
18507    pub fn open_excerpts_in_split(
18508        &mut self,
18509        _: &OpenExcerptsSplit,
18510        window: &mut Window,
18511        cx: &mut Context<Self>,
18512    ) {
18513        self.open_excerpts_common(None, true, window, cx)
18514    }
18515
18516    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18517        self.open_excerpts_common(None, false, window, cx)
18518    }
18519
18520    fn open_excerpts_common(
18521        &mut self,
18522        jump_data: Option<JumpData>,
18523        split: bool,
18524        window: &mut Window,
18525        cx: &mut Context<Self>,
18526    ) {
18527        let Some(workspace) = self.workspace() else {
18528            cx.propagate();
18529            return;
18530        };
18531
18532        if self.buffer.read(cx).is_singleton() {
18533            cx.propagate();
18534            return;
18535        }
18536
18537        let mut new_selections_by_buffer = HashMap::default();
18538        match &jump_data {
18539            Some(JumpData::MultiBufferPoint {
18540                excerpt_id,
18541                position,
18542                anchor,
18543                line_offset_from_top,
18544            }) => {
18545                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18546                if let Some(buffer) = multi_buffer_snapshot
18547                    .buffer_id_for_excerpt(*excerpt_id)
18548                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18549                {
18550                    let buffer_snapshot = buffer.read(cx).snapshot();
18551                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18552                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18553                    } else {
18554                        buffer_snapshot.clip_point(*position, Bias::Left)
18555                    };
18556                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18557                    new_selections_by_buffer.insert(
18558                        buffer,
18559                        (
18560                            vec![jump_to_offset..jump_to_offset],
18561                            Some(*line_offset_from_top),
18562                        ),
18563                    );
18564                }
18565            }
18566            Some(JumpData::MultiBufferRow {
18567                row,
18568                line_offset_from_top,
18569            }) => {
18570                let point = MultiBufferPoint::new(row.0, 0);
18571                if let Some((buffer, buffer_point, _)) =
18572                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18573                {
18574                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18575                    new_selections_by_buffer
18576                        .entry(buffer)
18577                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18578                        .0
18579                        .push(buffer_offset..buffer_offset)
18580                }
18581            }
18582            None => {
18583                let selections = self.selections.all::<usize>(cx);
18584                let multi_buffer = self.buffer.read(cx);
18585                for selection in selections {
18586                    for (snapshot, range, _, anchor) in multi_buffer
18587                        .snapshot(cx)
18588                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18589                    {
18590                        if let Some(anchor) = anchor {
18591                            // selection is in a deleted hunk
18592                            let Some(buffer_id) = anchor.buffer_id else {
18593                                continue;
18594                            };
18595                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18596                                continue;
18597                            };
18598                            let offset = text::ToOffset::to_offset(
18599                                &anchor.text_anchor,
18600                                &buffer_handle.read(cx).snapshot(),
18601                            );
18602                            let range = offset..offset;
18603                            new_selections_by_buffer
18604                                .entry(buffer_handle)
18605                                .or_insert((Vec::new(), None))
18606                                .0
18607                                .push(range)
18608                        } else {
18609                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18610                            else {
18611                                continue;
18612                            };
18613                            new_selections_by_buffer
18614                                .entry(buffer_handle)
18615                                .or_insert((Vec::new(), None))
18616                                .0
18617                                .push(range)
18618                        }
18619                    }
18620                }
18621            }
18622        }
18623
18624        new_selections_by_buffer
18625            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18626
18627        if new_selections_by_buffer.is_empty() {
18628            return;
18629        }
18630
18631        // We defer the pane interaction because we ourselves are a workspace item
18632        // and activating a new item causes the pane to call a method on us reentrantly,
18633        // which panics if we're on the stack.
18634        window.defer(cx, move |window, cx| {
18635            workspace.update(cx, |workspace, cx| {
18636                let pane = if split {
18637                    workspace.adjacent_pane(window, cx)
18638                } else {
18639                    workspace.active_pane().clone()
18640                };
18641
18642                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18643                    let editor = buffer
18644                        .read(cx)
18645                        .file()
18646                        .is_none()
18647                        .then(|| {
18648                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18649                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18650                            // Instead, we try to activate the existing editor in the pane first.
18651                            let (editor, pane_item_index) =
18652                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18653                                    let editor = item.downcast::<Editor>()?;
18654                                    let singleton_buffer =
18655                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18656                                    if singleton_buffer == buffer {
18657                                        Some((editor, i))
18658                                    } else {
18659                                        None
18660                                    }
18661                                })?;
18662                            pane.update(cx, |pane, cx| {
18663                                pane.activate_item(pane_item_index, true, true, window, cx)
18664                            });
18665                            Some(editor)
18666                        })
18667                        .flatten()
18668                        .unwrap_or_else(|| {
18669                            workspace.open_project_item::<Self>(
18670                                pane.clone(),
18671                                buffer,
18672                                true,
18673                                true,
18674                                window,
18675                                cx,
18676                            )
18677                        });
18678
18679                    editor.update(cx, |editor, cx| {
18680                        let autoscroll = match scroll_offset {
18681                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18682                            None => Autoscroll::newest(),
18683                        };
18684                        let nav_history = editor.nav_history.take();
18685                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18686                            s.select_ranges(ranges);
18687                        });
18688                        editor.nav_history = nav_history;
18689                    });
18690                }
18691            })
18692        });
18693    }
18694
18695    // For now, don't allow opening excerpts in buffers that aren't backed by
18696    // regular project files.
18697    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18698        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18699    }
18700
18701    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18702        let snapshot = self.buffer.read(cx).read(cx);
18703        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18704        Some(
18705            ranges
18706                .iter()
18707                .map(move |range| {
18708                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18709                })
18710                .collect(),
18711        )
18712    }
18713
18714    fn selection_replacement_ranges(
18715        &self,
18716        range: Range<OffsetUtf16>,
18717        cx: &mut App,
18718    ) -> Vec<Range<OffsetUtf16>> {
18719        let selections = self.selections.all::<OffsetUtf16>(cx);
18720        let newest_selection = selections
18721            .iter()
18722            .max_by_key(|selection| selection.id)
18723            .unwrap();
18724        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18725        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18726        let snapshot = self.buffer.read(cx).read(cx);
18727        selections
18728            .into_iter()
18729            .map(|mut selection| {
18730                selection.start.0 =
18731                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18732                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18733                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18734                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18735            })
18736            .collect()
18737    }
18738
18739    fn report_editor_event(
18740        &self,
18741        event_type: &'static str,
18742        file_extension: Option<String>,
18743        cx: &App,
18744    ) {
18745        if cfg!(any(test, feature = "test-support")) {
18746            return;
18747        }
18748
18749        let Some(project) = &self.project else { return };
18750
18751        // If None, we are in a file without an extension
18752        let file = self
18753            .buffer
18754            .read(cx)
18755            .as_singleton()
18756            .and_then(|b| b.read(cx).file());
18757        let file_extension = file_extension.or(file
18758            .as_ref()
18759            .and_then(|file| Path::new(file.file_name(cx)).extension())
18760            .and_then(|e| e.to_str())
18761            .map(|a| a.to_string()));
18762
18763        let vim_mode = vim_enabled(cx);
18764
18765        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18766        let copilot_enabled = edit_predictions_provider
18767            == language::language_settings::EditPredictionProvider::Copilot;
18768        let copilot_enabled_for_language = self
18769            .buffer
18770            .read(cx)
18771            .language_settings(cx)
18772            .show_edit_predictions;
18773
18774        let project = project.read(cx);
18775        telemetry::event!(
18776            event_type,
18777            file_extension,
18778            vim_mode,
18779            copilot_enabled,
18780            copilot_enabled_for_language,
18781            edit_predictions_provider,
18782            is_via_ssh = project.is_via_ssh(),
18783        );
18784    }
18785
18786    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
18787    /// with each line being an array of {text, highlight} objects.
18788    fn copy_highlight_json(
18789        &mut self,
18790        _: &CopyHighlightJson,
18791        window: &mut Window,
18792        cx: &mut Context<Self>,
18793    ) {
18794        #[derive(Serialize)]
18795        struct Chunk<'a> {
18796            text: String,
18797            highlight: Option<&'a str>,
18798        }
18799
18800        let snapshot = self.buffer.read(cx).snapshot(cx);
18801        let range = self
18802            .selected_text_range(false, window, cx)
18803            .and_then(|selection| {
18804                if selection.range.is_empty() {
18805                    None
18806                } else {
18807                    Some(selection.range)
18808                }
18809            })
18810            .unwrap_or_else(|| 0..snapshot.len());
18811
18812        let chunks = snapshot.chunks(range, true);
18813        let mut lines = Vec::new();
18814        let mut line: VecDeque<Chunk> = VecDeque::new();
18815
18816        let Some(style) = self.style.as_ref() else {
18817            return;
18818        };
18819
18820        for chunk in chunks {
18821            let highlight = chunk
18822                .syntax_highlight_id
18823                .and_then(|id| id.name(&style.syntax));
18824            let mut chunk_lines = chunk.text.split('\n').peekable();
18825            while let Some(text) = chunk_lines.next() {
18826                let mut merged_with_last_token = false;
18827                if let Some(last_token) = line.back_mut() {
18828                    if last_token.highlight == highlight {
18829                        last_token.text.push_str(text);
18830                        merged_with_last_token = true;
18831                    }
18832                }
18833
18834                if !merged_with_last_token {
18835                    line.push_back(Chunk {
18836                        text: text.into(),
18837                        highlight,
18838                    });
18839                }
18840
18841                if chunk_lines.peek().is_some() {
18842                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
18843                        line.pop_front();
18844                    }
18845                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
18846                        line.pop_back();
18847                    }
18848
18849                    lines.push(mem::take(&mut line));
18850                }
18851            }
18852        }
18853
18854        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
18855            return;
18856        };
18857        cx.write_to_clipboard(ClipboardItem::new_string(lines));
18858    }
18859
18860    pub fn open_context_menu(
18861        &mut self,
18862        _: &OpenContextMenu,
18863        window: &mut Window,
18864        cx: &mut Context<Self>,
18865    ) {
18866        self.request_autoscroll(Autoscroll::newest(), cx);
18867        let position = self.selections.newest_display(cx).start;
18868        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
18869    }
18870
18871    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
18872        &self.inlay_hint_cache
18873    }
18874
18875    pub fn replay_insert_event(
18876        &mut self,
18877        text: &str,
18878        relative_utf16_range: Option<Range<isize>>,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881    ) {
18882        if !self.input_enabled {
18883            cx.emit(EditorEvent::InputIgnored { text: text.into() });
18884            return;
18885        }
18886        if let Some(relative_utf16_range) = relative_utf16_range {
18887            let selections = self.selections.all::<OffsetUtf16>(cx);
18888            self.change_selections(None, window, cx, |s| {
18889                let new_ranges = selections.into_iter().map(|range| {
18890                    let start = OffsetUtf16(
18891                        range
18892                            .head()
18893                            .0
18894                            .saturating_add_signed(relative_utf16_range.start),
18895                    );
18896                    let end = OffsetUtf16(
18897                        range
18898                            .head()
18899                            .0
18900                            .saturating_add_signed(relative_utf16_range.end),
18901                    );
18902                    start..end
18903                });
18904                s.select_ranges(new_ranges);
18905            });
18906        }
18907
18908        self.handle_input(text, window, cx);
18909    }
18910
18911    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
18912        let Some(provider) = self.semantics_provider.as_ref() else {
18913            return false;
18914        };
18915
18916        let mut supports = false;
18917        self.buffer().update(cx, |this, cx| {
18918            this.for_each_buffer(|buffer| {
18919                supports |= provider.supports_inlay_hints(buffer, cx);
18920            });
18921        });
18922
18923        supports
18924    }
18925
18926    pub fn is_focused(&self, window: &Window) -> bool {
18927        self.focus_handle.is_focused(window)
18928    }
18929
18930    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18931        cx.emit(EditorEvent::Focused);
18932
18933        if let Some(descendant) = self
18934            .last_focused_descendant
18935            .take()
18936            .and_then(|descendant| descendant.upgrade())
18937        {
18938            window.focus(&descendant);
18939        } else {
18940            if let Some(blame) = self.blame.as_ref() {
18941                blame.update(cx, GitBlame::focus)
18942            }
18943
18944            self.blink_manager.update(cx, BlinkManager::enable);
18945            self.show_cursor_names(window, cx);
18946            self.buffer.update(cx, |buffer, cx| {
18947                buffer.finalize_last_transaction(cx);
18948                if self.leader_id.is_none() {
18949                    buffer.set_active_selections(
18950                        &self.selections.disjoint_anchors(),
18951                        self.selections.line_mode,
18952                        self.cursor_shape,
18953                        cx,
18954                    );
18955                }
18956            });
18957        }
18958    }
18959
18960    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
18961        cx.emit(EditorEvent::FocusedIn)
18962    }
18963
18964    fn handle_focus_out(
18965        &mut self,
18966        event: FocusOutEvent,
18967        _window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        if event.blurred != self.focus_handle {
18971            self.last_focused_descendant = Some(event.blurred);
18972        }
18973        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
18974    }
18975
18976    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18977        self.blink_manager.update(cx, BlinkManager::disable);
18978        self.buffer
18979            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
18980
18981        if let Some(blame) = self.blame.as_ref() {
18982            blame.update(cx, GitBlame::blur)
18983        }
18984        if !self.hover_state.focused(window, cx) {
18985            hide_hover(self, cx);
18986        }
18987        if !self
18988            .context_menu
18989            .borrow()
18990            .as_ref()
18991            .is_some_and(|context_menu| context_menu.focused(window, cx))
18992        {
18993            self.hide_context_menu(window, cx);
18994        }
18995        self.discard_inline_completion(false, cx);
18996        cx.emit(EditorEvent::Blurred);
18997        cx.notify();
18998    }
18999
19000    pub fn register_action<A: Action>(
19001        &mut self,
19002        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19003    ) -> Subscription {
19004        let id = self.next_editor_action_id.post_inc();
19005        let listener = Arc::new(listener);
19006        self.editor_actions.borrow_mut().insert(
19007            id,
19008            Box::new(move |window, _| {
19009                let listener = listener.clone();
19010                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19011                    let action = action.downcast_ref().unwrap();
19012                    if phase == DispatchPhase::Bubble {
19013                        listener(action, window, cx)
19014                    }
19015                })
19016            }),
19017        );
19018
19019        let editor_actions = self.editor_actions.clone();
19020        Subscription::new(move || {
19021            editor_actions.borrow_mut().remove(&id);
19022        })
19023    }
19024
19025    pub fn file_header_size(&self) -> u32 {
19026        FILE_HEADER_HEIGHT
19027    }
19028
19029    pub fn restore(
19030        &mut self,
19031        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19032        window: &mut Window,
19033        cx: &mut Context<Self>,
19034    ) {
19035        let workspace = self.workspace();
19036        let project = self.project.as_ref();
19037        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19038            let mut tasks = Vec::new();
19039            for (buffer_id, changes) in revert_changes {
19040                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19041                    buffer.update(cx, |buffer, cx| {
19042                        buffer.edit(
19043                            changes
19044                                .into_iter()
19045                                .map(|(range, text)| (range, text.to_string())),
19046                            None,
19047                            cx,
19048                        );
19049                    });
19050
19051                    if let Some(project) =
19052                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19053                    {
19054                        project.update(cx, |project, cx| {
19055                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19056                        })
19057                    }
19058                }
19059            }
19060            tasks
19061        });
19062        cx.spawn_in(window, async move |_, cx| {
19063            for (buffer, task) in save_tasks {
19064                let result = task.await;
19065                if result.is_err() {
19066                    let Some(path) = buffer
19067                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19068                        .ok()
19069                    else {
19070                        continue;
19071                    };
19072                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19073                        let Some(task) = cx
19074                            .update_window_entity(&workspace, |workspace, window, cx| {
19075                                workspace
19076                                    .open_path_preview(path, None, false, false, false, window, cx)
19077                            })
19078                            .ok()
19079                        else {
19080                            continue;
19081                        };
19082                        task.await.log_err();
19083                    }
19084                }
19085            }
19086        })
19087        .detach();
19088        self.change_selections(None, window, cx, |selections| selections.refresh());
19089    }
19090
19091    pub fn to_pixel_point(
19092        &self,
19093        source: multi_buffer::Anchor,
19094        editor_snapshot: &EditorSnapshot,
19095        window: &mut Window,
19096    ) -> Option<gpui::Point<Pixels>> {
19097        let source_point = source.to_display_point(editor_snapshot);
19098        self.display_to_pixel_point(source_point, editor_snapshot, window)
19099    }
19100
19101    pub fn display_to_pixel_point(
19102        &self,
19103        source: DisplayPoint,
19104        editor_snapshot: &EditorSnapshot,
19105        window: &mut Window,
19106    ) -> Option<gpui::Point<Pixels>> {
19107        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19108        let text_layout_details = self.text_layout_details(window);
19109        let scroll_top = text_layout_details
19110            .scroll_anchor
19111            .scroll_position(editor_snapshot)
19112            .y;
19113
19114        if source.row().as_f32() < scroll_top.floor() {
19115            return None;
19116        }
19117        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19118        let source_y = line_height * (source.row().as_f32() - scroll_top);
19119        Some(gpui::Point::new(source_x, source_y))
19120    }
19121
19122    pub fn has_visible_completions_menu(&self) -> bool {
19123        !self.edit_prediction_preview_is_active()
19124            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19125                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19126            })
19127    }
19128
19129    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19130        if self.mode.is_minimap() {
19131            return;
19132        }
19133        self.addons
19134            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19135    }
19136
19137    pub fn unregister_addon<T: Addon>(&mut self) {
19138        self.addons.remove(&std::any::TypeId::of::<T>());
19139    }
19140
19141    pub fn addon<T: Addon>(&self) -> Option<&T> {
19142        let type_id = std::any::TypeId::of::<T>();
19143        self.addons
19144            .get(&type_id)
19145            .and_then(|item| item.to_any().downcast_ref::<T>())
19146    }
19147
19148    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19149        let type_id = std::any::TypeId::of::<T>();
19150        self.addons
19151            .get_mut(&type_id)
19152            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19153    }
19154
19155    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19156        let text_layout_details = self.text_layout_details(window);
19157        let style = &text_layout_details.editor_style;
19158        let font_id = window.text_system().resolve_font(&style.text.font());
19159        let font_size = style.text.font_size.to_pixels(window.rem_size());
19160        let line_height = style.text.line_height_in_pixels(window.rem_size());
19161        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19162
19163        gpui::Size::new(em_width, line_height)
19164    }
19165
19166    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19167        self.load_diff_task.clone()
19168    }
19169
19170    fn read_metadata_from_db(
19171        &mut self,
19172        item_id: u64,
19173        workspace_id: WorkspaceId,
19174        window: &mut Window,
19175        cx: &mut Context<Editor>,
19176    ) {
19177        if self.is_singleton(cx)
19178            && !self.mode.is_minimap()
19179            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19180        {
19181            let buffer_snapshot = OnceCell::new();
19182
19183            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19184                if !folds.is_empty() {
19185                    let snapshot =
19186                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19187                    self.fold_ranges(
19188                        folds
19189                            .into_iter()
19190                            .map(|(start, end)| {
19191                                snapshot.clip_offset(start, Bias::Left)
19192                                    ..snapshot.clip_offset(end, Bias::Right)
19193                            })
19194                            .collect(),
19195                        false,
19196                        window,
19197                        cx,
19198                    );
19199                }
19200            }
19201
19202            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19203                if !selections.is_empty() {
19204                    let snapshot =
19205                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19206                    self.change_selections(None, window, cx, |s| {
19207                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19208                            snapshot.clip_offset(start, Bias::Left)
19209                                ..snapshot.clip_offset(end, Bias::Right)
19210                        }));
19211                    });
19212                }
19213            };
19214        }
19215
19216        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19217    }
19218}
19219
19220fn vim_enabled(cx: &App) -> bool {
19221    cx.global::<SettingsStore>()
19222        .raw_user_settings()
19223        .get("vim_mode")
19224        == Some(&serde_json::Value::Bool(true))
19225}
19226
19227// Consider user intent and default settings
19228fn choose_completion_range(
19229    completion: &Completion,
19230    intent: CompletionIntent,
19231    buffer: &Entity<Buffer>,
19232    cx: &mut Context<Editor>,
19233) -> Range<usize> {
19234    fn should_replace(
19235        completion: &Completion,
19236        insert_range: &Range<text::Anchor>,
19237        intent: CompletionIntent,
19238        completion_mode_setting: LspInsertMode,
19239        buffer: &Buffer,
19240    ) -> bool {
19241        // specific actions take precedence over settings
19242        match intent {
19243            CompletionIntent::CompleteWithInsert => return false,
19244            CompletionIntent::CompleteWithReplace => return true,
19245            CompletionIntent::Complete | CompletionIntent::Compose => {}
19246        }
19247
19248        match completion_mode_setting {
19249            LspInsertMode::Insert => false,
19250            LspInsertMode::Replace => true,
19251            LspInsertMode::ReplaceSubsequence => {
19252                let mut text_to_replace = buffer.chars_for_range(
19253                    buffer.anchor_before(completion.replace_range.start)
19254                        ..buffer.anchor_after(completion.replace_range.end),
19255                );
19256                let mut completion_text = completion.new_text.chars();
19257
19258                // is `text_to_replace` a subsequence of `completion_text`
19259                text_to_replace
19260                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19261            }
19262            LspInsertMode::ReplaceSuffix => {
19263                let range_after_cursor = insert_range.end..completion.replace_range.end;
19264
19265                let text_after_cursor = buffer
19266                    .text_for_range(
19267                        buffer.anchor_before(range_after_cursor.start)
19268                            ..buffer.anchor_after(range_after_cursor.end),
19269                    )
19270                    .collect::<String>();
19271                completion.new_text.ends_with(&text_after_cursor)
19272            }
19273        }
19274    }
19275
19276    let buffer = buffer.read(cx);
19277
19278    if let CompletionSource::Lsp {
19279        insert_range: Some(insert_range),
19280        ..
19281    } = &completion.source
19282    {
19283        let completion_mode_setting =
19284            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19285                .completions
19286                .lsp_insert_mode;
19287
19288        if !should_replace(
19289            completion,
19290            &insert_range,
19291            intent,
19292            completion_mode_setting,
19293            buffer,
19294        ) {
19295            return insert_range.to_offset(buffer);
19296        }
19297    }
19298
19299    completion.replace_range.to_offset(buffer)
19300}
19301
19302fn insert_extra_newline_brackets(
19303    buffer: &MultiBufferSnapshot,
19304    range: Range<usize>,
19305    language: &language::LanguageScope,
19306) -> bool {
19307    let leading_whitespace_len = buffer
19308        .reversed_chars_at(range.start)
19309        .take_while(|c| c.is_whitespace() && *c != '\n')
19310        .map(|c| c.len_utf8())
19311        .sum::<usize>();
19312    let trailing_whitespace_len = buffer
19313        .chars_at(range.end)
19314        .take_while(|c| c.is_whitespace() && *c != '\n')
19315        .map(|c| c.len_utf8())
19316        .sum::<usize>();
19317    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19318
19319    language.brackets().any(|(pair, enabled)| {
19320        let pair_start = pair.start.trim_end();
19321        let pair_end = pair.end.trim_start();
19322
19323        enabled
19324            && pair.newline
19325            && buffer.contains_str_at(range.end, pair_end)
19326            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19327    })
19328}
19329
19330fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19331    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19332        [(buffer, range, _)] => (*buffer, range.clone()),
19333        _ => return false,
19334    };
19335    let pair = {
19336        let mut result: Option<BracketMatch> = None;
19337
19338        for pair in buffer
19339            .all_bracket_ranges(range.clone())
19340            .filter(move |pair| {
19341                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19342            })
19343        {
19344            let len = pair.close_range.end - pair.open_range.start;
19345
19346            if let Some(existing) = &result {
19347                let existing_len = existing.close_range.end - existing.open_range.start;
19348                if len > existing_len {
19349                    continue;
19350                }
19351            }
19352
19353            result = Some(pair);
19354        }
19355
19356        result
19357    };
19358    let Some(pair) = pair else {
19359        return false;
19360    };
19361    pair.newline_only
19362        && buffer
19363            .chars_for_range(pair.open_range.end..range.start)
19364            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19365            .all(|c| c.is_whitespace() && c != '\n')
19366}
19367
19368fn update_uncommitted_diff_for_buffer(
19369    editor: Entity<Editor>,
19370    project: &Entity<Project>,
19371    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19372    buffer: Entity<MultiBuffer>,
19373    cx: &mut App,
19374) -> Task<()> {
19375    let mut tasks = Vec::new();
19376    project.update(cx, |project, cx| {
19377        for buffer in buffers {
19378            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19379                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19380            }
19381        }
19382    });
19383    cx.spawn(async move |cx| {
19384        let diffs = future::join_all(tasks).await;
19385        if editor
19386            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19387            .unwrap_or(false)
19388        {
19389            return;
19390        }
19391
19392        buffer
19393            .update(cx, |buffer, cx| {
19394                for diff in diffs.into_iter().flatten() {
19395                    buffer.add_diff(diff, cx);
19396                }
19397            })
19398            .ok();
19399    })
19400}
19401
19402fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19403    let tab_size = tab_size.get() as usize;
19404    let mut width = offset;
19405
19406    for ch in text.chars() {
19407        width += if ch == '\t' {
19408            tab_size - (width % tab_size)
19409        } else {
19410            1
19411        };
19412    }
19413
19414    width - offset
19415}
19416
19417#[cfg(test)]
19418mod tests {
19419    use super::*;
19420
19421    #[test]
19422    fn test_string_size_with_expanded_tabs() {
19423        let nz = |val| NonZeroU32::new(val).unwrap();
19424        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19425        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19426        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19427        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19428        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19429        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19430        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19431        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19432    }
19433}
19434
19435/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19436struct WordBreakingTokenizer<'a> {
19437    input: &'a str,
19438}
19439
19440impl<'a> WordBreakingTokenizer<'a> {
19441    fn new(input: &'a str) -> Self {
19442        Self { input }
19443    }
19444}
19445
19446fn is_char_ideographic(ch: char) -> bool {
19447    use unicode_script::Script::*;
19448    use unicode_script::UnicodeScript;
19449    matches!(ch.script(), Han | Tangut | Yi)
19450}
19451
19452fn is_grapheme_ideographic(text: &str) -> bool {
19453    text.chars().any(is_char_ideographic)
19454}
19455
19456fn is_grapheme_whitespace(text: &str) -> bool {
19457    text.chars().any(|x| x.is_whitespace())
19458}
19459
19460fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19461    text.chars().next().map_or(false, |ch| {
19462        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19463    })
19464}
19465
19466#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19467enum WordBreakToken<'a> {
19468    Word { token: &'a str, grapheme_len: usize },
19469    InlineWhitespace { token: &'a str, grapheme_len: usize },
19470    Newline,
19471}
19472
19473impl<'a> Iterator for WordBreakingTokenizer<'a> {
19474    /// Yields a span, the count of graphemes in the token, and whether it was
19475    /// whitespace. Note that it also breaks at word boundaries.
19476    type Item = WordBreakToken<'a>;
19477
19478    fn next(&mut self) -> Option<Self::Item> {
19479        use unicode_segmentation::UnicodeSegmentation;
19480        if self.input.is_empty() {
19481            return None;
19482        }
19483
19484        let mut iter = self.input.graphemes(true).peekable();
19485        let mut offset = 0;
19486        let mut grapheme_len = 0;
19487        if let Some(first_grapheme) = iter.next() {
19488            let is_newline = first_grapheme == "\n";
19489            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19490            offset += first_grapheme.len();
19491            grapheme_len += 1;
19492            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19493                if let Some(grapheme) = iter.peek().copied() {
19494                    if should_stay_with_preceding_ideograph(grapheme) {
19495                        offset += grapheme.len();
19496                        grapheme_len += 1;
19497                    }
19498                }
19499            } else {
19500                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19501                let mut next_word_bound = words.peek().copied();
19502                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19503                    next_word_bound = words.next();
19504                }
19505                while let Some(grapheme) = iter.peek().copied() {
19506                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19507                        break;
19508                    };
19509                    if is_grapheme_whitespace(grapheme) != is_whitespace
19510                        || (grapheme == "\n") != is_newline
19511                    {
19512                        break;
19513                    };
19514                    offset += grapheme.len();
19515                    grapheme_len += 1;
19516                    iter.next();
19517                }
19518            }
19519            let token = &self.input[..offset];
19520            self.input = &self.input[offset..];
19521            if token == "\n" {
19522                Some(WordBreakToken::Newline)
19523            } else if is_whitespace {
19524                Some(WordBreakToken::InlineWhitespace {
19525                    token,
19526                    grapheme_len,
19527                })
19528            } else {
19529                Some(WordBreakToken::Word {
19530                    token,
19531                    grapheme_len,
19532                })
19533            }
19534        } else {
19535            None
19536        }
19537    }
19538}
19539
19540#[test]
19541fn test_word_breaking_tokenizer() {
19542    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19543        ("", &[]),
19544        ("  ", &[whitespace("  ", 2)]),
19545        ("Ʒ", &[word("Ʒ", 1)]),
19546        ("Ǽ", &[word("Ǽ", 1)]),
19547        ("", &[word("", 1)]),
19548        ("⋑⋑", &[word("⋑⋑", 2)]),
19549        (
19550            "原理,进而",
19551            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19552        ),
19553        (
19554            "hello world",
19555            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19556        ),
19557        (
19558            "hello, world",
19559            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19560        ),
19561        (
19562            "  hello world",
19563            &[
19564                whitespace("  ", 2),
19565                word("hello", 5),
19566                whitespace(" ", 1),
19567                word("world", 5),
19568            ],
19569        ),
19570        (
19571            "这是什么 \n 钢笔",
19572            &[
19573                word("", 1),
19574                word("", 1),
19575                word("", 1),
19576                word("", 1),
19577                whitespace(" ", 1),
19578                newline(),
19579                whitespace(" ", 1),
19580                word("", 1),
19581                word("", 1),
19582            ],
19583        ),
19584        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19585    ];
19586
19587    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19588        WordBreakToken::Word {
19589            token,
19590            grapheme_len,
19591        }
19592    }
19593
19594    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19595        WordBreakToken::InlineWhitespace {
19596            token,
19597            grapheme_len,
19598        }
19599    }
19600
19601    fn newline() -> WordBreakToken<'static> {
19602        WordBreakToken::Newline
19603    }
19604
19605    for (input, result) in tests {
19606        assert_eq!(
19607            WordBreakingTokenizer::new(input)
19608                .collect::<Vec<_>>()
19609                .as_slice(),
19610            *result,
19611        );
19612    }
19613}
19614
19615fn wrap_with_prefix(
19616    line_prefix: String,
19617    unwrapped_text: String,
19618    wrap_column: usize,
19619    tab_size: NonZeroU32,
19620    preserve_existing_whitespace: bool,
19621) -> String {
19622    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19623    let mut wrapped_text = String::new();
19624    let mut current_line = line_prefix.clone();
19625
19626    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19627    let mut current_line_len = line_prefix_len;
19628    let mut in_whitespace = false;
19629    for token in tokenizer {
19630        let have_preceding_whitespace = in_whitespace;
19631        match token {
19632            WordBreakToken::Word {
19633                token,
19634                grapheme_len,
19635            } => {
19636                in_whitespace = false;
19637                if current_line_len + grapheme_len > wrap_column
19638                    && current_line_len != line_prefix_len
19639                {
19640                    wrapped_text.push_str(current_line.trim_end());
19641                    wrapped_text.push('\n');
19642                    current_line.truncate(line_prefix.len());
19643                    current_line_len = line_prefix_len;
19644                }
19645                current_line.push_str(token);
19646                current_line_len += grapheme_len;
19647            }
19648            WordBreakToken::InlineWhitespace {
19649                mut token,
19650                mut grapheme_len,
19651            } => {
19652                in_whitespace = true;
19653                if have_preceding_whitespace && !preserve_existing_whitespace {
19654                    continue;
19655                }
19656                if !preserve_existing_whitespace {
19657                    token = " ";
19658                    grapheme_len = 1;
19659                }
19660                if current_line_len + grapheme_len > wrap_column {
19661                    wrapped_text.push_str(current_line.trim_end());
19662                    wrapped_text.push('\n');
19663                    current_line.truncate(line_prefix.len());
19664                    current_line_len = line_prefix_len;
19665                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19666                    current_line.push_str(token);
19667                    current_line_len += grapheme_len;
19668                }
19669            }
19670            WordBreakToken::Newline => {
19671                in_whitespace = true;
19672                if preserve_existing_whitespace {
19673                    wrapped_text.push_str(current_line.trim_end());
19674                    wrapped_text.push('\n');
19675                    current_line.truncate(line_prefix.len());
19676                    current_line_len = line_prefix_len;
19677                } else if have_preceding_whitespace {
19678                    continue;
19679                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19680                {
19681                    wrapped_text.push_str(current_line.trim_end());
19682                    wrapped_text.push('\n');
19683                    current_line.truncate(line_prefix.len());
19684                    current_line_len = line_prefix_len;
19685                } else if current_line_len != line_prefix_len {
19686                    current_line.push(' ');
19687                    current_line_len += 1;
19688                }
19689            }
19690        }
19691    }
19692
19693    if !current_line.is_empty() {
19694        wrapped_text.push_str(&current_line);
19695    }
19696    wrapped_text
19697}
19698
19699#[test]
19700fn test_wrap_with_prefix() {
19701    assert_eq!(
19702        wrap_with_prefix(
19703            "# ".to_string(),
19704            "abcdefg".to_string(),
19705            4,
19706            NonZeroU32::new(4).unwrap(),
19707            false,
19708        ),
19709        "# abcdefg"
19710    );
19711    assert_eq!(
19712        wrap_with_prefix(
19713            "".to_string(),
19714            "\thello world".to_string(),
19715            8,
19716            NonZeroU32::new(4).unwrap(),
19717            false,
19718        ),
19719        "hello\nworld"
19720    );
19721    assert_eq!(
19722        wrap_with_prefix(
19723            "// ".to_string(),
19724            "xx \nyy zz aa bb cc".to_string(),
19725            12,
19726            NonZeroU32::new(4).unwrap(),
19727            false,
19728        ),
19729        "// xx yy zz\n// aa bb cc"
19730    );
19731    assert_eq!(
19732        wrap_with_prefix(
19733            String::new(),
19734            "这是什么 \n 钢笔".to_string(),
19735            3,
19736            NonZeroU32::new(4).unwrap(),
19737            false,
19738        ),
19739        "这是什\n么 钢\n"
19740    );
19741}
19742
19743pub trait CollaborationHub {
19744    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19745    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19746    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19747}
19748
19749impl CollaborationHub for Entity<Project> {
19750    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19751        self.read(cx).collaborators()
19752    }
19753
19754    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19755        self.read(cx).user_store().read(cx).participant_indices()
19756    }
19757
19758    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19759        let this = self.read(cx);
19760        let user_ids = this.collaborators().values().map(|c| c.user_id);
19761        this.user_store().read_with(cx, |user_store, cx| {
19762            user_store.participant_names(user_ids, cx)
19763        })
19764    }
19765}
19766
19767pub trait SemanticsProvider {
19768    fn hover(
19769        &self,
19770        buffer: &Entity<Buffer>,
19771        position: text::Anchor,
19772        cx: &mut App,
19773    ) -> Option<Task<Vec<project::Hover>>>;
19774
19775    fn inline_values(
19776        &self,
19777        buffer_handle: Entity<Buffer>,
19778        range: Range<text::Anchor>,
19779        cx: &mut App,
19780    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19781
19782    fn inlay_hints(
19783        &self,
19784        buffer_handle: Entity<Buffer>,
19785        range: Range<text::Anchor>,
19786        cx: &mut App,
19787    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19788
19789    fn resolve_inlay_hint(
19790        &self,
19791        hint: InlayHint,
19792        buffer_handle: Entity<Buffer>,
19793        server_id: LanguageServerId,
19794        cx: &mut App,
19795    ) -> Option<Task<anyhow::Result<InlayHint>>>;
19796
19797    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
19798
19799    fn document_highlights(
19800        &self,
19801        buffer: &Entity<Buffer>,
19802        position: text::Anchor,
19803        cx: &mut App,
19804    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
19805
19806    fn definitions(
19807        &self,
19808        buffer: &Entity<Buffer>,
19809        position: text::Anchor,
19810        kind: GotoDefinitionKind,
19811        cx: &mut App,
19812    ) -> Option<Task<Result<Vec<LocationLink>>>>;
19813
19814    fn range_for_rename(
19815        &self,
19816        buffer: &Entity<Buffer>,
19817        position: text::Anchor,
19818        cx: &mut App,
19819    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
19820
19821    fn perform_rename(
19822        &self,
19823        buffer: &Entity<Buffer>,
19824        position: text::Anchor,
19825        new_name: String,
19826        cx: &mut App,
19827    ) -> Option<Task<Result<ProjectTransaction>>>;
19828}
19829
19830pub trait CompletionProvider {
19831    fn completions(
19832        &self,
19833        excerpt_id: ExcerptId,
19834        buffer: &Entity<Buffer>,
19835        buffer_position: text::Anchor,
19836        trigger: CompletionContext,
19837        window: &mut Window,
19838        cx: &mut Context<Editor>,
19839    ) -> Task<Result<Option<Vec<Completion>>>>;
19840
19841    fn resolve_completions(
19842        &self,
19843        buffer: Entity<Buffer>,
19844        completion_indices: Vec<usize>,
19845        completions: Rc<RefCell<Box<[Completion]>>>,
19846        cx: &mut Context<Editor>,
19847    ) -> Task<Result<bool>>;
19848
19849    fn apply_additional_edits_for_completion(
19850        &self,
19851        _buffer: Entity<Buffer>,
19852        _completions: Rc<RefCell<Box<[Completion]>>>,
19853        _completion_index: usize,
19854        _push_to_history: bool,
19855        _cx: &mut Context<Editor>,
19856    ) -> Task<Result<Option<language::Transaction>>> {
19857        Task::ready(Ok(None))
19858    }
19859
19860    fn is_completion_trigger(
19861        &self,
19862        buffer: &Entity<Buffer>,
19863        position: language::Anchor,
19864        text: &str,
19865        trigger_in_words: bool,
19866        cx: &mut Context<Editor>,
19867    ) -> bool;
19868
19869    fn sort_completions(&self) -> bool {
19870        true
19871    }
19872
19873    fn filter_completions(&self) -> bool {
19874        true
19875    }
19876}
19877
19878pub trait CodeActionProvider {
19879    fn id(&self) -> Arc<str>;
19880
19881    fn code_actions(
19882        &self,
19883        buffer: &Entity<Buffer>,
19884        range: Range<text::Anchor>,
19885        window: &mut Window,
19886        cx: &mut App,
19887    ) -> Task<Result<Vec<CodeAction>>>;
19888
19889    fn apply_code_action(
19890        &self,
19891        buffer_handle: Entity<Buffer>,
19892        action: CodeAction,
19893        excerpt_id: ExcerptId,
19894        push_to_history: bool,
19895        window: &mut Window,
19896        cx: &mut App,
19897    ) -> Task<Result<ProjectTransaction>>;
19898}
19899
19900impl CodeActionProvider for Entity<Project> {
19901    fn id(&self) -> Arc<str> {
19902        "project".into()
19903    }
19904
19905    fn code_actions(
19906        &self,
19907        buffer: &Entity<Buffer>,
19908        range: Range<text::Anchor>,
19909        _window: &mut Window,
19910        cx: &mut App,
19911    ) -> Task<Result<Vec<CodeAction>>> {
19912        self.update(cx, |project, cx| {
19913            let code_lens = project.code_lens(buffer, range.clone(), cx);
19914            let code_actions = project.code_actions(buffer, range, None, cx);
19915            cx.background_spawn(async move {
19916                let (code_lens, code_actions) = join(code_lens, code_actions).await;
19917                Ok(code_lens
19918                    .context("code lens fetch")?
19919                    .into_iter()
19920                    .chain(code_actions.context("code action fetch")?)
19921                    .collect())
19922            })
19923        })
19924    }
19925
19926    fn apply_code_action(
19927        &self,
19928        buffer_handle: Entity<Buffer>,
19929        action: CodeAction,
19930        _excerpt_id: ExcerptId,
19931        push_to_history: bool,
19932        _window: &mut Window,
19933        cx: &mut App,
19934    ) -> Task<Result<ProjectTransaction>> {
19935        self.update(cx, |project, cx| {
19936            project.apply_code_action(buffer_handle, action, push_to_history, cx)
19937        })
19938    }
19939}
19940
19941fn snippet_completions(
19942    project: &Project,
19943    buffer: &Entity<Buffer>,
19944    buffer_position: text::Anchor,
19945    cx: &mut App,
19946) -> Task<Result<Vec<Completion>>> {
19947    let languages = buffer.read(cx).languages_at(buffer_position);
19948    let snippet_store = project.snippets().read(cx);
19949
19950    let scopes: Vec<_> = languages
19951        .iter()
19952        .filter_map(|language| {
19953            let language_name = language.lsp_id();
19954            let snippets = snippet_store.snippets_for(Some(language_name), cx);
19955
19956            if snippets.is_empty() {
19957                None
19958            } else {
19959                Some((language.default_scope(), snippets))
19960            }
19961        })
19962        .collect();
19963
19964    if scopes.is_empty() {
19965        return Task::ready(Ok(vec![]));
19966    }
19967
19968    let snapshot = buffer.read(cx).text_snapshot();
19969    let chars: String = snapshot
19970        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
19971        .collect();
19972    let executor = cx.background_executor().clone();
19973
19974    cx.background_spawn(async move {
19975        let mut all_results: Vec<Completion> = Vec::new();
19976        for (scope, snippets) in scopes.into_iter() {
19977            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
19978            let mut last_word = chars
19979                .chars()
19980                .take_while(|c| classifier.is_word(*c))
19981                .collect::<String>();
19982            last_word = last_word.chars().rev().collect();
19983
19984            if last_word.is_empty() {
19985                return Ok(vec![]);
19986            }
19987
19988            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
19989            let to_lsp = |point: &text::Anchor| {
19990                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
19991                point_to_lsp(end)
19992            };
19993            let lsp_end = to_lsp(&buffer_position);
19994
19995            let candidates = snippets
19996                .iter()
19997                .enumerate()
19998                .flat_map(|(ix, snippet)| {
19999                    snippet
20000                        .prefix
20001                        .iter()
20002                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20003                })
20004                .collect::<Vec<StringMatchCandidate>>();
20005
20006            let mut matches = fuzzy::match_strings(
20007                &candidates,
20008                &last_word,
20009                last_word.chars().any(|c| c.is_uppercase()),
20010                100,
20011                &Default::default(),
20012                executor.clone(),
20013            )
20014            .await;
20015
20016            // Remove all candidates where the query's start does not match the start of any word in the candidate
20017            if let Some(query_start) = last_word.chars().next() {
20018                matches.retain(|string_match| {
20019                    split_words(&string_match.string).any(|word| {
20020                        // Check that the first codepoint of the word as lowercase matches the first
20021                        // codepoint of the query as lowercase
20022                        word.chars()
20023                            .flat_map(|codepoint| codepoint.to_lowercase())
20024                            .zip(query_start.to_lowercase())
20025                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20026                    })
20027                });
20028            }
20029
20030            let matched_strings = matches
20031                .into_iter()
20032                .map(|m| m.string)
20033                .collect::<HashSet<_>>();
20034
20035            let mut result: Vec<Completion> = snippets
20036                .iter()
20037                .filter_map(|snippet| {
20038                    let matching_prefix = snippet
20039                        .prefix
20040                        .iter()
20041                        .find(|prefix| matched_strings.contains(*prefix))?;
20042                    let start = as_offset - last_word.len();
20043                    let start = snapshot.anchor_before(start);
20044                    let range = start..buffer_position;
20045                    let lsp_start = to_lsp(&start);
20046                    let lsp_range = lsp::Range {
20047                        start: lsp_start,
20048                        end: lsp_end,
20049                    };
20050                    Some(Completion {
20051                        replace_range: range,
20052                        new_text: snippet.body.clone(),
20053                        source: CompletionSource::Lsp {
20054                            insert_range: None,
20055                            server_id: LanguageServerId(usize::MAX),
20056                            resolved: true,
20057                            lsp_completion: Box::new(lsp::CompletionItem {
20058                                label: snippet.prefix.first().unwrap().clone(),
20059                                kind: Some(CompletionItemKind::SNIPPET),
20060                                label_details: snippet.description.as_ref().map(|description| {
20061                                    lsp::CompletionItemLabelDetails {
20062                                        detail: Some(description.clone()),
20063                                        description: None,
20064                                    }
20065                                }),
20066                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20067                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20068                                    lsp::InsertReplaceEdit {
20069                                        new_text: snippet.body.clone(),
20070                                        insert: lsp_range,
20071                                        replace: lsp_range,
20072                                    },
20073                                )),
20074                                filter_text: Some(snippet.body.clone()),
20075                                sort_text: Some(char::MAX.to_string()),
20076                                ..lsp::CompletionItem::default()
20077                            }),
20078                            lsp_defaults: None,
20079                        },
20080                        label: CodeLabel {
20081                            text: matching_prefix.clone(),
20082                            runs: Vec::new(),
20083                            filter_range: 0..matching_prefix.len(),
20084                        },
20085                        icon_path: None,
20086                        documentation: Some(
20087                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20088                                single_line: snippet.name.clone().into(),
20089                                plain_text: snippet
20090                                    .description
20091                                    .clone()
20092                                    .map(|description| description.into()),
20093                            },
20094                        ),
20095                        insert_text_mode: None,
20096                        confirm: None,
20097                    })
20098                })
20099                .collect();
20100
20101            all_results.append(&mut result);
20102        }
20103
20104        Ok(all_results)
20105    })
20106}
20107
20108impl CompletionProvider for Entity<Project> {
20109    fn completions(
20110        &self,
20111        _excerpt_id: ExcerptId,
20112        buffer: &Entity<Buffer>,
20113        buffer_position: text::Anchor,
20114        options: CompletionContext,
20115        _window: &mut Window,
20116        cx: &mut Context<Editor>,
20117    ) -> Task<Result<Option<Vec<Completion>>>> {
20118        self.update(cx, |project, cx| {
20119            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20120            let project_completions = project.completions(buffer, buffer_position, options, cx);
20121            cx.background_spawn(async move {
20122                let snippets_completions = snippets.await?;
20123                match project_completions.await? {
20124                    Some(mut completions) => {
20125                        completions.extend(snippets_completions);
20126                        Ok(Some(completions))
20127                    }
20128                    None => {
20129                        if snippets_completions.is_empty() {
20130                            Ok(None)
20131                        } else {
20132                            Ok(Some(snippets_completions))
20133                        }
20134                    }
20135                }
20136            })
20137        })
20138    }
20139
20140    fn resolve_completions(
20141        &self,
20142        buffer: Entity<Buffer>,
20143        completion_indices: Vec<usize>,
20144        completions: Rc<RefCell<Box<[Completion]>>>,
20145        cx: &mut Context<Editor>,
20146    ) -> Task<Result<bool>> {
20147        self.update(cx, |project, cx| {
20148            project.lsp_store().update(cx, |lsp_store, cx| {
20149                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20150            })
20151        })
20152    }
20153
20154    fn apply_additional_edits_for_completion(
20155        &self,
20156        buffer: Entity<Buffer>,
20157        completions: Rc<RefCell<Box<[Completion]>>>,
20158        completion_index: usize,
20159        push_to_history: bool,
20160        cx: &mut Context<Editor>,
20161    ) -> Task<Result<Option<language::Transaction>>> {
20162        self.update(cx, |project, cx| {
20163            project.lsp_store().update(cx, |lsp_store, cx| {
20164                lsp_store.apply_additional_edits_for_completion(
20165                    buffer,
20166                    completions,
20167                    completion_index,
20168                    push_to_history,
20169                    cx,
20170                )
20171            })
20172        })
20173    }
20174
20175    fn is_completion_trigger(
20176        &self,
20177        buffer: &Entity<Buffer>,
20178        position: language::Anchor,
20179        text: &str,
20180        trigger_in_words: bool,
20181        cx: &mut Context<Editor>,
20182    ) -> bool {
20183        let mut chars = text.chars();
20184        let char = if let Some(char) = chars.next() {
20185            char
20186        } else {
20187            return false;
20188        };
20189        if chars.next().is_some() {
20190            return false;
20191        }
20192
20193        let buffer = buffer.read(cx);
20194        let snapshot = buffer.snapshot();
20195        if !snapshot.settings_at(position, cx).show_completions_on_input {
20196            return false;
20197        }
20198        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20199        if trigger_in_words && classifier.is_word(char) {
20200            return true;
20201        }
20202
20203        buffer.completion_triggers().contains(text)
20204    }
20205}
20206
20207impl SemanticsProvider for Entity<Project> {
20208    fn hover(
20209        &self,
20210        buffer: &Entity<Buffer>,
20211        position: text::Anchor,
20212        cx: &mut App,
20213    ) -> Option<Task<Vec<project::Hover>>> {
20214        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20215    }
20216
20217    fn document_highlights(
20218        &self,
20219        buffer: &Entity<Buffer>,
20220        position: text::Anchor,
20221        cx: &mut App,
20222    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20223        Some(self.update(cx, |project, cx| {
20224            project.document_highlights(buffer, position, cx)
20225        }))
20226    }
20227
20228    fn definitions(
20229        &self,
20230        buffer: &Entity<Buffer>,
20231        position: text::Anchor,
20232        kind: GotoDefinitionKind,
20233        cx: &mut App,
20234    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20235        Some(self.update(cx, |project, cx| match kind {
20236            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20237            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20238            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20239            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20240        }))
20241    }
20242
20243    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20244        // TODO: make this work for remote projects
20245        self.update(cx, |project, cx| {
20246            if project
20247                .active_debug_session(cx)
20248                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20249            {
20250                return true;
20251            }
20252
20253            buffer.update(cx, |buffer, cx| {
20254                project.any_language_server_supports_inlay_hints(buffer, cx)
20255            })
20256        })
20257    }
20258
20259    fn inline_values(
20260        &self,
20261        buffer_handle: Entity<Buffer>,
20262
20263        range: Range<text::Anchor>,
20264        cx: &mut App,
20265    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20266        self.update(cx, |project, cx| {
20267            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20268
20269            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20270        })
20271    }
20272
20273    fn inlay_hints(
20274        &self,
20275        buffer_handle: Entity<Buffer>,
20276        range: Range<text::Anchor>,
20277        cx: &mut App,
20278    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20279        Some(self.update(cx, |project, cx| {
20280            project.inlay_hints(buffer_handle, range, cx)
20281        }))
20282    }
20283
20284    fn resolve_inlay_hint(
20285        &self,
20286        hint: InlayHint,
20287        buffer_handle: Entity<Buffer>,
20288        server_id: LanguageServerId,
20289        cx: &mut App,
20290    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20291        Some(self.update(cx, |project, cx| {
20292            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20293        }))
20294    }
20295
20296    fn range_for_rename(
20297        &self,
20298        buffer: &Entity<Buffer>,
20299        position: text::Anchor,
20300        cx: &mut App,
20301    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20302        Some(self.update(cx, |project, cx| {
20303            let buffer = buffer.clone();
20304            let task = project.prepare_rename(buffer.clone(), position, cx);
20305            cx.spawn(async move |_, cx| {
20306                Ok(match task.await? {
20307                    PrepareRenameResponse::Success(range) => Some(range),
20308                    PrepareRenameResponse::InvalidPosition => None,
20309                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20310                        // Fallback on using TreeSitter info to determine identifier range
20311                        buffer.update(cx, |buffer, _| {
20312                            let snapshot = buffer.snapshot();
20313                            let (range, kind) = snapshot.surrounding_word(position);
20314                            if kind != Some(CharKind::Word) {
20315                                return None;
20316                            }
20317                            Some(
20318                                snapshot.anchor_before(range.start)
20319                                    ..snapshot.anchor_after(range.end),
20320                            )
20321                        })?
20322                    }
20323                })
20324            })
20325        }))
20326    }
20327
20328    fn perform_rename(
20329        &self,
20330        buffer: &Entity<Buffer>,
20331        position: text::Anchor,
20332        new_name: String,
20333        cx: &mut App,
20334    ) -> Option<Task<Result<ProjectTransaction>>> {
20335        Some(self.update(cx, |project, cx| {
20336            project.perform_rename(buffer.clone(), position, new_name, cx)
20337        }))
20338    }
20339}
20340
20341fn inlay_hint_settings(
20342    location: Anchor,
20343    snapshot: &MultiBufferSnapshot,
20344    cx: &mut Context<Editor>,
20345) -> InlayHintSettings {
20346    let file = snapshot.file_at(location);
20347    let language = snapshot.language_at(location).map(|l| l.name());
20348    language_settings(language, file, cx).inlay_hints
20349}
20350
20351fn consume_contiguous_rows(
20352    contiguous_row_selections: &mut Vec<Selection<Point>>,
20353    selection: &Selection<Point>,
20354    display_map: &DisplaySnapshot,
20355    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20356) -> (MultiBufferRow, MultiBufferRow) {
20357    contiguous_row_selections.push(selection.clone());
20358    let start_row = MultiBufferRow(selection.start.row);
20359    let mut end_row = ending_row(selection, display_map);
20360
20361    while let Some(next_selection) = selections.peek() {
20362        if next_selection.start.row <= end_row.0 {
20363            end_row = ending_row(next_selection, display_map);
20364            contiguous_row_selections.push(selections.next().unwrap().clone());
20365        } else {
20366            break;
20367        }
20368    }
20369    (start_row, end_row)
20370}
20371
20372fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20373    if next_selection.end.column > 0 || next_selection.is_empty() {
20374        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20375    } else {
20376        MultiBufferRow(next_selection.end.row)
20377    }
20378}
20379
20380impl EditorSnapshot {
20381    pub fn remote_selections_in_range<'a>(
20382        &'a self,
20383        range: &'a Range<Anchor>,
20384        collaboration_hub: &dyn CollaborationHub,
20385        cx: &'a App,
20386    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20387        let participant_names = collaboration_hub.user_names(cx);
20388        let participant_indices = collaboration_hub.user_participant_indices(cx);
20389        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20390        let collaborators_by_replica_id = collaborators_by_peer_id
20391            .values()
20392            .map(|collaborator| (collaborator.replica_id, collaborator))
20393            .collect::<HashMap<_, _>>();
20394        self.buffer_snapshot
20395            .selections_in_range(range, false)
20396            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20397                if replica_id == AGENT_REPLICA_ID {
20398                    Some(RemoteSelection {
20399                        replica_id,
20400                        selection,
20401                        cursor_shape,
20402                        line_mode,
20403                        collaborator_id: CollaboratorId::Agent,
20404                        user_name: Some("Agent".into()),
20405                        color: cx.theme().players().agent(),
20406                    })
20407                } else {
20408                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20409                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20410                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20411                    Some(RemoteSelection {
20412                        replica_id,
20413                        selection,
20414                        cursor_shape,
20415                        line_mode,
20416                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20417                        user_name,
20418                        color: if let Some(index) = participant_index {
20419                            cx.theme().players().color_for_participant(index.0)
20420                        } else {
20421                            cx.theme().players().absent()
20422                        },
20423                    })
20424                }
20425            })
20426    }
20427
20428    pub fn hunks_for_ranges(
20429        &self,
20430        ranges: impl IntoIterator<Item = Range<Point>>,
20431    ) -> Vec<MultiBufferDiffHunk> {
20432        let mut hunks = Vec::new();
20433        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20434            HashMap::default();
20435        for query_range in ranges {
20436            let query_rows =
20437                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20438            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20439                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20440            ) {
20441                // Include deleted hunks that are adjacent to the query range, because
20442                // otherwise they would be missed.
20443                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20444                if hunk.status().is_deleted() {
20445                    intersects_range |= hunk.row_range.start == query_rows.end;
20446                    intersects_range |= hunk.row_range.end == query_rows.start;
20447                }
20448                if intersects_range {
20449                    if !processed_buffer_rows
20450                        .entry(hunk.buffer_id)
20451                        .or_default()
20452                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20453                    {
20454                        continue;
20455                    }
20456                    hunks.push(hunk);
20457                }
20458            }
20459        }
20460
20461        hunks
20462    }
20463
20464    fn display_diff_hunks_for_rows<'a>(
20465        &'a self,
20466        display_rows: Range<DisplayRow>,
20467        folded_buffers: &'a HashSet<BufferId>,
20468    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20469        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20470        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20471
20472        self.buffer_snapshot
20473            .diff_hunks_in_range(buffer_start..buffer_end)
20474            .filter_map(|hunk| {
20475                if folded_buffers.contains(&hunk.buffer_id) {
20476                    return None;
20477                }
20478
20479                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20480                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20481
20482                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20483                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20484
20485                let display_hunk = if hunk_display_start.column() != 0 {
20486                    DisplayDiffHunk::Folded {
20487                        display_row: hunk_display_start.row(),
20488                    }
20489                } else {
20490                    let mut end_row = hunk_display_end.row();
20491                    if hunk_display_end.column() > 0 {
20492                        end_row.0 += 1;
20493                    }
20494                    let is_created_file = hunk.is_created_file();
20495                    DisplayDiffHunk::Unfolded {
20496                        status: hunk.status(),
20497                        diff_base_byte_range: hunk.diff_base_byte_range,
20498                        display_row_range: hunk_display_start.row()..end_row,
20499                        multi_buffer_range: Anchor::range_in_buffer(
20500                            hunk.excerpt_id,
20501                            hunk.buffer_id,
20502                            hunk.buffer_range,
20503                        ),
20504                        is_created_file,
20505                    }
20506                };
20507
20508                Some(display_hunk)
20509            })
20510    }
20511
20512    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20513        self.display_snapshot.buffer_snapshot.language_at(position)
20514    }
20515
20516    pub fn is_focused(&self) -> bool {
20517        self.is_focused
20518    }
20519
20520    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20521        self.placeholder_text.as_ref()
20522    }
20523
20524    pub fn scroll_position(&self) -> gpui::Point<f32> {
20525        self.scroll_anchor.scroll_position(&self.display_snapshot)
20526    }
20527
20528    fn gutter_dimensions(
20529        &self,
20530        font_id: FontId,
20531        font_size: Pixels,
20532        max_line_number_width: Pixels,
20533        cx: &App,
20534    ) -> Option<GutterDimensions> {
20535        if !self.show_gutter {
20536            return None;
20537        }
20538
20539        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20540        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20541
20542        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20543            matches!(
20544                ProjectSettings::get_global(cx).git.git_gutter,
20545                Some(GitGutterSetting::TrackedFiles)
20546            )
20547        });
20548        let gutter_settings = EditorSettings::get_global(cx).gutter;
20549        let show_line_numbers = self
20550            .show_line_numbers
20551            .unwrap_or(gutter_settings.line_numbers);
20552        let line_gutter_width = if show_line_numbers {
20553            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20554            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20555            max_line_number_width.max(min_width_for_number_on_gutter)
20556        } else {
20557            0.0.into()
20558        };
20559
20560        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20561        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20562
20563        let git_blame_entries_width =
20564            self.git_blame_gutter_max_author_length
20565                .map(|max_author_length| {
20566                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20567                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20568
20569                    /// The number of characters to dedicate to gaps and margins.
20570                    const SPACING_WIDTH: usize = 4;
20571
20572                    let max_char_count = max_author_length.min(renderer.max_author_length())
20573                        + ::git::SHORT_SHA_LENGTH
20574                        + MAX_RELATIVE_TIMESTAMP.len()
20575                        + SPACING_WIDTH;
20576
20577                    em_advance * max_char_count
20578                });
20579
20580        let is_singleton = self.buffer_snapshot.is_singleton();
20581
20582        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20583        left_padding += if !is_singleton {
20584            em_width * 4.0
20585        } else if show_runnables || show_breakpoints {
20586            em_width * 3.0
20587        } else if show_git_gutter && show_line_numbers {
20588            em_width * 2.0
20589        } else if show_git_gutter || show_line_numbers {
20590            em_width
20591        } else {
20592            px(0.)
20593        };
20594
20595        let shows_folds = is_singleton && gutter_settings.folds;
20596
20597        let right_padding = if shows_folds && show_line_numbers {
20598            em_width * 4.0
20599        } else if shows_folds || (!is_singleton && show_line_numbers) {
20600            em_width * 3.0
20601        } else if show_line_numbers {
20602            em_width
20603        } else {
20604            px(0.)
20605        };
20606
20607        Some(GutterDimensions {
20608            left_padding,
20609            right_padding,
20610            width: line_gutter_width + left_padding + right_padding,
20611            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20612            git_blame_entries_width,
20613        })
20614    }
20615
20616    pub fn render_crease_toggle(
20617        &self,
20618        buffer_row: MultiBufferRow,
20619        row_contains_cursor: bool,
20620        editor: Entity<Editor>,
20621        window: &mut Window,
20622        cx: &mut App,
20623    ) -> Option<AnyElement> {
20624        let folded = self.is_line_folded(buffer_row);
20625        let mut is_foldable = false;
20626
20627        if let Some(crease) = self
20628            .crease_snapshot
20629            .query_row(buffer_row, &self.buffer_snapshot)
20630        {
20631            is_foldable = true;
20632            match crease {
20633                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20634                    if let Some(render_toggle) = render_toggle {
20635                        let toggle_callback =
20636                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20637                                if folded {
20638                                    editor.update(cx, |editor, cx| {
20639                                        editor.fold_at(buffer_row, window, cx)
20640                                    });
20641                                } else {
20642                                    editor.update(cx, |editor, cx| {
20643                                        editor.unfold_at(buffer_row, window, cx)
20644                                    });
20645                                }
20646                            });
20647                        return Some((render_toggle)(
20648                            buffer_row,
20649                            folded,
20650                            toggle_callback,
20651                            window,
20652                            cx,
20653                        ));
20654                    }
20655                }
20656            }
20657        }
20658
20659        is_foldable |= self.starts_indent(buffer_row);
20660
20661        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20662            Some(
20663                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20664                    .toggle_state(folded)
20665                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20666                        if folded {
20667                            this.unfold_at(buffer_row, window, cx);
20668                        } else {
20669                            this.fold_at(buffer_row, window, cx);
20670                        }
20671                    }))
20672                    .into_any_element(),
20673            )
20674        } else {
20675            None
20676        }
20677    }
20678
20679    pub fn render_crease_trailer(
20680        &self,
20681        buffer_row: MultiBufferRow,
20682        window: &mut Window,
20683        cx: &mut App,
20684    ) -> Option<AnyElement> {
20685        let folded = self.is_line_folded(buffer_row);
20686        if let Crease::Inline { render_trailer, .. } = self
20687            .crease_snapshot
20688            .query_row(buffer_row, &self.buffer_snapshot)?
20689        {
20690            let render_trailer = render_trailer.as_ref()?;
20691            Some(render_trailer(buffer_row, folded, window, cx))
20692        } else {
20693            None
20694        }
20695    }
20696}
20697
20698impl Deref for EditorSnapshot {
20699    type Target = DisplaySnapshot;
20700
20701    fn deref(&self) -> &Self::Target {
20702        &self.display_snapshot
20703    }
20704}
20705
20706#[derive(Clone, Debug, PartialEq, Eq)]
20707pub enum EditorEvent {
20708    InputIgnored {
20709        text: Arc<str>,
20710    },
20711    InputHandled {
20712        utf16_range_to_replace: Option<Range<isize>>,
20713        text: Arc<str>,
20714    },
20715    ExcerptsAdded {
20716        buffer: Entity<Buffer>,
20717        predecessor: ExcerptId,
20718        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20719    },
20720    ExcerptsRemoved {
20721        ids: Vec<ExcerptId>,
20722        removed_buffer_ids: Vec<BufferId>,
20723    },
20724    BufferFoldToggled {
20725        ids: Vec<ExcerptId>,
20726        folded: bool,
20727    },
20728    ExcerptsEdited {
20729        ids: Vec<ExcerptId>,
20730    },
20731    ExcerptsExpanded {
20732        ids: Vec<ExcerptId>,
20733    },
20734    BufferEdited,
20735    Edited {
20736        transaction_id: clock::Lamport,
20737    },
20738    Reparsed(BufferId),
20739    Focused,
20740    FocusedIn,
20741    Blurred,
20742    DirtyChanged,
20743    Saved,
20744    TitleChanged,
20745    DiffBaseChanged,
20746    SelectionsChanged {
20747        local: bool,
20748    },
20749    ScrollPositionChanged {
20750        local: bool,
20751        autoscroll: bool,
20752    },
20753    Closed,
20754    TransactionUndone {
20755        transaction_id: clock::Lamport,
20756    },
20757    TransactionBegun {
20758        transaction_id: clock::Lamport,
20759    },
20760    Reloaded,
20761    CursorShapeChanged,
20762    PushedToNavHistory {
20763        anchor: Anchor,
20764        is_deactivate: bool,
20765    },
20766}
20767
20768impl EventEmitter<EditorEvent> for Editor {}
20769
20770impl Focusable for Editor {
20771    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20772        self.focus_handle.clone()
20773    }
20774}
20775
20776impl Render for Editor {
20777    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20778        let settings = ThemeSettings::get_global(cx);
20779
20780        let mut text_style = match self.mode {
20781            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
20782                color: cx.theme().colors().editor_foreground,
20783                font_family: settings.ui_font.family.clone(),
20784                font_features: settings.ui_font.features.clone(),
20785                font_fallbacks: settings.ui_font.fallbacks.clone(),
20786                font_size: rems(0.875).into(),
20787                font_weight: settings.ui_font.weight,
20788                line_height: relative(settings.buffer_line_height.value()),
20789                ..Default::default()
20790            },
20791            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
20792                color: cx.theme().colors().editor_foreground,
20793                font_family: settings.buffer_font.family.clone(),
20794                font_features: settings.buffer_font.features.clone(),
20795                font_fallbacks: settings.buffer_font.fallbacks.clone(),
20796                font_size: settings.buffer_font_size(cx).into(),
20797                font_weight: settings.buffer_font.weight,
20798                line_height: relative(settings.buffer_line_height.value()),
20799                ..Default::default()
20800            },
20801        };
20802        if let Some(text_style_refinement) = &self.text_style_refinement {
20803            text_style.refine(text_style_refinement)
20804        }
20805
20806        let background = match self.mode {
20807            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
20808            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
20809            EditorMode::Full { .. } => cx.theme().colors().editor_background,
20810            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
20811        };
20812
20813        EditorElement::new(
20814            &cx.entity(),
20815            EditorStyle {
20816                background,
20817                local_player: cx.theme().players().local(),
20818                text: text_style,
20819                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
20820                syntax: cx.theme().syntax().clone(),
20821                status: cx.theme().status().clone(),
20822                inlay_hints_style: make_inlay_hints_style(cx),
20823                inline_completion_styles: make_suggestion_styles(cx),
20824                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
20825                show_underlines: !self.mode.is_minimap(),
20826            },
20827        )
20828    }
20829}
20830
20831impl EntityInputHandler for Editor {
20832    fn text_for_range(
20833        &mut self,
20834        range_utf16: Range<usize>,
20835        adjusted_range: &mut Option<Range<usize>>,
20836        _: &mut Window,
20837        cx: &mut Context<Self>,
20838    ) -> Option<String> {
20839        let snapshot = self.buffer.read(cx).read(cx);
20840        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
20841        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
20842        if (start.0..end.0) != range_utf16 {
20843            adjusted_range.replace(start.0..end.0);
20844        }
20845        Some(snapshot.text_for_range(start..end).collect())
20846    }
20847
20848    fn selected_text_range(
20849        &mut self,
20850        ignore_disabled_input: bool,
20851        _: &mut Window,
20852        cx: &mut Context<Self>,
20853    ) -> Option<UTF16Selection> {
20854        // Prevent the IME menu from appearing when holding down an alphabetic key
20855        // while input is disabled.
20856        if !ignore_disabled_input && !self.input_enabled {
20857            return None;
20858        }
20859
20860        let selection = self.selections.newest::<OffsetUtf16>(cx);
20861        let range = selection.range();
20862
20863        Some(UTF16Selection {
20864            range: range.start.0..range.end.0,
20865            reversed: selection.reversed,
20866        })
20867    }
20868
20869    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
20870        let snapshot = self.buffer.read(cx).read(cx);
20871        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
20872        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
20873    }
20874
20875    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20876        self.clear_highlights::<InputComposition>(cx);
20877        self.ime_transaction.take();
20878    }
20879
20880    fn replace_text_in_range(
20881        &mut self,
20882        range_utf16: Option<Range<usize>>,
20883        text: &str,
20884        window: &mut Window,
20885        cx: &mut Context<Self>,
20886    ) {
20887        if !self.input_enabled {
20888            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20889            return;
20890        }
20891
20892        self.transact(window, cx, |this, window, cx| {
20893            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
20894                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20895                Some(this.selection_replacement_ranges(range_utf16, cx))
20896            } else {
20897                this.marked_text_ranges(cx)
20898            };
20899
20900            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
20901                let newest_selection_id = this.selections.newest_anchor().id;
20902                this.selections
20903                    .all::<OffsetUtf16>(cx)
20904                    .iter()
20905                    .zip(ranges_to_replace.iter())
20906                    .find_map(|(selection, range)| {
20907                        if selection.id == newest_selection_id {
20908                            Some(
20909                                (range.start.0 as isize - selection.head().0 as isize)
20910                                    ..(range.end.0 as isize - selection.head().0 as isize),
20911                            )
20912                        } else {
20913                            None
20914                        }
20915                    })
20916            });
20917
20918            cx.emit(EditorEvent::InputHandled {
20919                utf16_range_to_replace: range_to_replace,
20920                text: text.into(),
20921            });
20922
20923            if let Some(new_selected_ranges) = new_selected_ranges {
20924                this.change_selections(None, window, cx, |selections| {
20925                    selections.select_ranges(new_selected_ranges)
20926                });
20927                this.backspace(&Default::default(), window, cx);
20928            }
20929
20930            this.handle_input(text, window, cx);
20931        });
20932
20933        if let Some(transaction) = self.ime_transaction {
20934            self.buffer.update(cx, |buffer, cx| {
20935                buffer.group_until_transaction(transaction, cx);
20936            });
20937        }
20938
20939        self.unmark_text(window, cx);
20940    }
20941
20942    fn replace_and_mark_text_in_range(
20943        &mut self,
20944        range_utf16: Option<Range<usize>>,
20945        text: &str,
20946        new_selected_range_utf16: Option<Range<usize>>,
20947        window: &mut Window,
20948        cx: &mut Context<Self>,
20949    ) {
20950        if !self.input_enabled {
20951            return;
20952        }
20953
20954        let transaction = self.transact(window, cx, |this, window, cx| {
20955            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
20956                let snapshot = this.buffer.read(cx).read(cx);
20957                if let Some(relative_range_utf16) = range_utf16.as_ref() {
20958                    for marked_range in &mut marked_ranges {
20959                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
20960                        marked_range.start.0 += relative_range_utf16.start;
20961                        marked_range.start =
20962                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
20963                        marked_range.end =
20964                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
20965                    }
20966                }
20967                Some(marked_ranges)
20968            } else if let Some(range_utf16) = range_utf16 {
20969                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
20970                Some(this.selection_replacement_ranges(range_utf16, cx))
20971            } else {
20972                None
20973            };
20974
20975            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
20976                let newest_selection_id = this.selections.newest_anchor().id;
20977                this.selections
20978                    .all::<OffsetUtf16>(cx)
20979                    .iter()
20980                    .zip(ranges_to_replace.iter())
20981                    .find_map(|(selection, range)| {
20982                        if selection.id == newest_selection_id {
20983                            Some(
20984                                (range.start.0 as isize - selection.head().0 as isize)
20985                                    ..(range.end.0 as isize - selection.head().0 as isize),
20986                            )
20987                        } else {
20988                            None
20989                        }
20990                    })
20991            });
20992
20993            cx.emit(EditorEvent::InputHandled {
20994                utf16_range_to_replace: range_to_replace,
20995                text: text.into(),
20996            });
20997
20998            if let Some(ranges) = ranges_to_replace {
20999                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21000            }
21001
21002            let marked_ranges = {
21003                let snapshot = this.buffer.read(cx).read(cx);
21004                this.selections
21005                    .disjoint_anchors()
21006                    .iter()
21007                    .map(|selection| {
21008                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21009                    })
21010                    .collect::<Vec<_>>()
21011            };
21012
21013            if text.is_empty() {
21014                this.unmark_text(window, cx);
21015            } else {
21016                this.highlight_text::<InputComposition>(
21017                    marked_ranges.clone(),
21018                    HighlightStyle {
21019                        underline: Some(UnderlineStyle {
21020                            thickness: px(1.),
21021                            color: None,
21022                            wavy: false,
21023                        }),
21024                        ..Default::default()
21025                    },
21026                    cx,
21027                );
21028            }
21029
21030            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21031            let use_autoclose = this.use_autoclose;
21032            let use_auto_surround = this.use_auto_surround;
21033            this.set_use_autoclose(false);
21034            this.set_use_auto_surround(false);
21035            this.handle_input(text, window, cx);
21036            this.set_use_autoclose(use_autoclose);
21037            this.set_use_auto_surround(use_auto_surround);
21038
21039            if let Some(new_selected_range) = new_selected_range_utf16 {
21040                let snapshot = this.buffer.read(cx).read(cx);
21041                let new_selected_ranges = marked_ranges
21042                    .into_iter()
21043                    .map(|marked_range| {
21044                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21045                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21046                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21047                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21048                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21049                    })
21050                    .collect::<Vec<_>>();
21051
21052                drop(snapshot);
21053                this.change_selections(None, window, cx, |selections| {
21054                    selections.select_ranges(new_selected_ranges)
21055                });
21056            }
21057        });
21058
21059        self.ime_transaction = self.ime_transaction.or(transaction);
21060        if let Some(transaction) = self.ime_transaction {
21061            self.buffer.update(cx, |buffer, cx| {
21062                buffer.group_until_transaction(transaction, cx);
21063            });
21064        }
21065
21066        if self.text_highlights::<InputComposition>(cx).is_none() {
21067            self.ime_transaction.take();
21068        }
21069    }
21070
21071    fn bounds_for_range(
21072        &mut self,
21073        range_utf16: Range<usize>,
21074        element_bounds: gpui::Bounds<Pixels>,
21075        window: &mut Window,
21076        cx: &mut Context<Self>,
21077    ) -> Option<gpui::Bounds<Pixels>> {
21078        let text_layout_details = self.text_layout_details(window);
21079        let gpui::Size {
21080            width: em_width,
21081            height: line_height,
21082        } = self.character_size(window);
21083
21084        let snapshot = self.snapshot(window, cx);
21085        let scroll_position = snapshot.scroll_position();
21086        let scroll_left = scroll_position.x * em_width;
21087
21088        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21089        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21090            + self.gutter_dimensions.width
21091            + self.gutter_dimensions.margin;
21092        let y = line_height * (start.row().as_f32() - scroll_position.y);
21093
21094        Some(Bounds {
21095            origin: element_bounds.origin + point(x, y),
21096            size: size(em_width, line_height),
21097        })
21098    }
21099
21100    fn character_index_for_point(
21101        &mut self,
21102        point: gpui::Point<Pixels>,
21103        _window: &mut Window,
21104        _cx: &mut Context<Self>,
21105    ) -> Option<usize> {
21106        let position_map = self.last_position_map.as_ref()?;
21107        if !position_map.text_hitbox.contains(&point) {
21108            return None;
21109        }
21110        let display_point = position_map.point_for_position(point).previous_valid;
21111        let anchor = position_map
21112            .snapshot
21113            .display_point_to_anchor(display_point, Bias::Left);
21114        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21115        Some(utf16_offset.0)
21116    }
21117}
21118
21119trait SelectionExt {
21120    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21121    fn spanned_rows(
21122        &self,
21123        include_end_if_at_line_start: bool,
21124        map: &DisplaySnapshot,
21125    ) -> Range<MultiBufferRow>;
21126}
21127
21128impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21129    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21130        let start = self
21131            .start
21132            .to_point(&map.buffer_snapshot)
21133            .to_display_point(map);
21134        let end = self
21135            .end
21136            .to_point(&map.buffer_snapshot)
21137            .to_display_point(map);
21138        if self.reversed {
21139            end..start
21140        } else {
21141            start..end
21142        }
21143    }
21144
21145    fn spanned_rows(
21146        &self,
21147        include_end_if_at_line_start: bool,
21148        map: &DisplaySnapshot,
21149    ) -> Range<MultiBufferRow> {
21150        let start = self.start.to_point(&map.buffer_snapshot);
21151        let mut end = self.end.to_point(&map.buffer_snapshot);
21152        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21153            end.row -= 1;
21154        }
21155
21156        let buffer_start = map.prev_line_boundary(start).0;
21157        let buffer_end = map.next_line_boundary(end).0;
21158        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21159    }
21160}
21161
21162impl<T: InvalidationRegion> InvalidationStack<T> {
21163    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21164    where
21165        S: Clone + ToOffset,
21166    {
21167        while let Some(region) = self.last() {
21168            let all_selections_inside_invalidation_ranges =
21169                if selections.len() == region.ranges().len() {
21170                    selections
21171                        .iter()
21172                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21173                        .all(|(selection, invalidation_range)| {
21174                            let head = selection.head().to_offset(buffer);
21175                            invalidation_range.start <= head && invalidation_range.end >= head
21176                        })
21177                } else {
21178                    false
21179                };
21180
21181            if all_selections_inside_invalidation_ranges {
21182                break;
21183            } else {
21184                self.pop();
21185            }
21186        }
21187    }
21188}
21189
21190impl<T> Default for InvalidationStack<T> {
21191    fn default() -> Self {
21192        Self(Default::default())
21193    }
21194}
21195
21196impl<T> Deref for InvalidationStack<T> {
21197    type Target = Vec<T>;
21198
21199    fn deref(&self) -> &Self::Target {
21200        &self.0
21201    }
21202}
21203
21204impl<T> DerefMut for InvalidationStack<T> {
21205    fn deref_mut(&mut self) -> &mut Self::Target {
21206        &mut self.0
21207    }
21208}
21209
21210impl InvalidationRegion for SnippetState {
21211    fn ranges(&self) -> &[Range<Anchor>] {
21212        &self.ranges[self.active_index]
21213    }
21214}
21215
21216fn inline_completion_edit_text(
21217    current_snapshot: &BufferSnapshot,
21218    edits: &[(Range<Anchor>, String)],
21219    edit_preview: &EditPreview,
21220    include_deletions: bool,
21221    cx: &App,
21222) -> HighlightedText {
21223    let edits = edits
21224        .iter()
21225        .map(|(anchor, text)| {
21226            (
21227                anchor.start.text_anchor..anchor.end.text_anchor,
21228                text.clone(),
21229            )
21230        })
21231        .collect::<Vec<_>>();
21232
21233    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21234}
21235
21236pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21237    match severity {
21238        lsp::DiagnosticSeverity::ERROR => colors.error,
21239        lsp::DiagnosticSeverity::WARNING => colors.warning,
21240        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21241        lsp::DiagnosticSeverity::HINT => colors.info,
21242        _ => colors.ignored,
21243    }
21244}
21245
21246pub fn styled_runs_for_code_label<'a>(
21247    label: &'a CodeLabel,
21248    syntax_theme: &'a theme::SyntaxTheme,
21249) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21250    let fade_out = HighlightStyle {
21251        fade_out: Some(0.35),
21252        ..Default::default()
21253    };
21254
21255    let mut prev_end = label.filter_range.end;
21256    label
21257        .runs
21258        .iter()
21259        .enumerate()
21260        .flat_map(move |(ix, (range, highlight_id))| {
21261            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21262                style
21263            } else {
21264                return Default::default();
21265            };
21266            let mut muted_style = style;
21267            muted_style.highlight(fade_out);
21268
21269            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21270            if range.start >= label.filter_range.end {
21271                if range.start > prev_end {
21272                    runs.push((prev_end..range.start, fade_out));
21273                }
21274                runs.push((range.clone(), muted_style));
21275            } else if range.end <= label.filter_range.end {
21276                runs.push((range.clone(), style));
21277            } else {
21278                runs.push((range.start..label.filter_range.end, style));
21279                runs.push((label.filter_range.end..range.end, muted_style));
21280            }
21281            prev_end = cmp::max(prev_end, range.end);
21282
21283            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21284                runs.push((prev_end..label.text.len(), fade_out));
21285            }
21286
21287            runs
21288        })
21289}
21290
21291pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21292    let mut prev_index = 0;
21293    let mut prev_codepoint: Option<char> = None;
21294    text.char_indices()
21295        .chain([(text.len(), '\0')])
21296        .filter_map(move |(index, codepoint)| {
21297            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21298            let is_boundary = index == text.len()
21299                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21300                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21301            if is_boundary {
21302                let chunk = &text[prev_index..index];
21303                prev_index = index;
21304                Some(chunk)
21305            } else {
21306                None
21307            }
21308        })
21309}
21310
21311pub trait RangeToAnchorExt: Sized {
21312    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21313
21314    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21315        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21316        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21317    }
21318}
21319
21320impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21321    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21322        let start_offset = self.start.to_offset(snapshot);
21323        let end_offset = self.end.to_offset(snapshot);
21324        if start_offset == end_offset {
21325            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21326        } else {
21327            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21328        }
21329    }
21330}
21331
21332pub trait RowExt {
21333    fn as_f32(&self) -> f32;
21334
21335    fn next_row(&self) -> Self;
21336
21337    fn previous_row(&self) -> Self;
21338
21339    fn minus(&self, other: Self) -> u32;
21340}
21341
21342impl RowExt for DisplayRow {
21343    fn as_f32(&self) -> f32 {
21344        self.0 as f32
21345    }
21346
21347    fn next_row(&self) -> Self {
21348        Self(self.0 + 1)
21349    }
21350
21351    fn previous_row(&self) -> Self {
21352        Self(self.0.saturating_sub(1))
21353    }
21354
21355    fn minus(&self, other: Self) -> u32 {
21356        self.0 - other.0
21357    }
21358}
21359
21360impl RowExt for MultiBufferRow {
21361    fn as_f32(&self) -> f32 {
21362        self.0 as f32
21363    }
21364
21365    fn next_row(&self) -> Self {
21366        Self(self.0 + 1)
21367    }
21368
21369    fn previous_row(&self) -> Self {
21370        Self(self.0.saturating_sub(1))
21371    }
21372
21373    fn minus(&self, other: Self) -> u32 {
21374        self.0 - other.0
21375    }
21376}
21377
21378trait RowRangeExt {
21379    type Row;
21380
21381    fn len(&self) -> usize;
21382
21383    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21384}
21385
21386impl RowRangeExt for Range<MultiBufferRow> {
21387    type Row = MultiBufferRow;
21388
21389    fn len(&self) -> usize {
21390        (self.end.0 - self.start.0) as usize
21391    }
21392
21393    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21394        (self.start.0..self.end.0).map(MultiBufferRow)
21395    }
21396}
21397
21398impl RowRangeExt for Range<DisplayRow> {
21399    type Row = DisplayRow;
21400
21401    fn len(&self) -> usize {
21402        (self.end.0 - self.start.0) as usize
21403    }
21404
21405    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21406        (self.start.0..self.end.0).map(DisplayRow)
21407    }
21408}
21409
21410/// If select range has more than one line, we
21411/// just point the cursor to range.start.
21412fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21413    if range.start.row == range.end.row {
21414        range
21415    } else {
21416        range.start..range.start
21417    }
21418}
21419pub struct KillRing(ClipboardItem);
21420impl Global for KillRing {}
21421
21422const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21423
21424enum BreakpointPromptEditAction {
21425    Log,
21426    Condition,
21427    HitCondition,
21428}
21429
21430struct BreakpointPromptEditor {
21431    pub(crate) prompt: Entity<Editor>,
21432    editor: WeakEntity<Editor>,
21433    breakpoint_anchor: Anchor,
21434    breakpoint: Breakpoint,
21435    edit_action: BreakpointPromptEditAction,
21436    block_ids: HashSet<CustomBlockId>,
21437    editor_margins: Arc<Mutex<EditorMargins>>,
21438    _subscriptions: Vec<Subscription>,
21439}
21440
21441impl BreakpointPromptEditor {
21442    const MAX_LINES: u8 = 4;
21443
21444    fn new(
21445        editor: WeakEntity<Editor>,
21446        breakpoint_anchor: Anchor,
21447        breakpoint: Breakpoint,
21448        edit_action: BreakpointPromptEditAction,
21449        window: &mut Window,
21450        cx: &mut Context<Self>,
21451    ) -> Self {
21452        let base_text = match edit_action {
21453            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21454            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21455            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21456        }
21457        .map(|msg| msg.to_string())
21458        .unwrap_or_default();
21459
21460        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21461        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21462
21463        let prompt = cx.new(|cx| {
21464            let mut prompt = Editor::new(
21465                EditorMode::AutoHeight {
21466                    max_lines: Self::MAX_LINES as usize,
21467                },
21468                buffer,
21469                None,
21470                window,
21471                cx,
21472            );
21473            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21474            prompt.set_show_cursor_when_unfocused(false, cx);
21475            prompt.set_placeholder_text(
21476                match edit_action {
21477                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21478                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21479                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21480                },
21481                cx,
21482            );
21483
21484            prompt
21485        });
21486
21487        Self {
21488            prompt,
21489            editor,
21490            breakpoint_anchor,
21491            breakpoint,
21492            edit_action,
21493            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21494            block_ids: Default::default(),
21495            _subscriptions: vec![],
21496        }
21497    }
21498
21499    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21500        self.block_ids.extend(block_ids)
21501    }
21502
21503    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21504        if let Some(editor) = self.editor.upgrade() {
21505            let message = self
21506                .prompt
21507                .read(cx)
21508                .buffer
21509                .read(cx)
21510                .as_singleton()
21511                .expect("A multi buffer in breakpoint prompt isn't possible")
21512                .read(cx)
21513                .as_rope()
21514                .to_string();
21515
21516            editor.update(cx, |editor, cx| {
21517                editor.edit_breakpoint_at_anchor(
21518                    self.breakpoint_anchor,
21519                    self.breakpoint.clone(),
21520                    match self.edit_action {
21521                        BreakpointPromptEditAction::Log => {
21522                            BreakpointEditAction::EditLogMessage(message.into())
21523                        }
21524                        BreakpointPromptEditAction::Condition => {
21525                            BreakpointEditAction::EditCondition(message.into())
21526                        }
21527                        BreakpointPromptEditAction::HitCondition => {
21528                            BreakpointEditAction::EditHitCondition(message.into())
21529                        }
21530                    },
21531                    cx,
21532                );
21533
21534                editor.remove_blocks(self.block_ids.clone(), None, cx);
21535                cx.focus_self(window);
21536            });
21537        }
21538    }
21539
21540    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21541        self.editor
21542            .update(cx, |editor, cx| {
21543                editor.remove_blocks(self.block_ids.clone(), None, cx);
21544                window.focus(&editor.focus_handle);
21545            })
21546            .log_err();
21547    }
21548
21549    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21550        let settings = ThemeSettings::get_global(cx);
21551        let text_style = TextStyle {
21552            color: if self.prompt.read(cx).read_only(cx) {
21553                cx.theme().colors().text_disabled
21554            } else {
21555                cx.theme().colors().text
21556            },
21557            font_family: settings.buffer_font.family.clone(),
21558            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21559            font_size: settings.buffer_font_size(cx).into(),
21560            font_weight: settings.buffer_font.weight,
21561            line_height: relative(settings.buffer_line_height.value()),
21562            ..Default::default()
21563        };
21564        EditorElement::new(
21565            &self.prompt,
21566            EditorStyle {
21567                background: cx.theme().colors().editor_background,
21568                local_player: cx.theme().players().local(),
21569                text: text_style,
21570                ..Default::default()
21571            },
21572        )
21573    }
21574}
21575
21576impl Render for BreakpointPromptEditor {
21577    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21578        let editor_margins = *self.editor_margins.lock();
21579        let gutter_dimensions = editor_margins.gutter;
21580        h_flex()
21581            .key_context("Editor")
21582            .bg(cx.theme().colors().editor_background)
21583            .border_y_1()
21584            .border_color(cx.theme().status().info_border)
21585            .size_full()
21586            .py(window.line_height() / 2.5)
21587            .on_action(cx.listener(Self::confirm))
21588            .on_action(cx.listener(Self::cancel))
21589            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21590            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21591    }
21592}
21593
21594impl Focusable for BreakpointPromptEditor {
21595    fn focus_handle(&self, cx: &App) -> FocusHandle {
21596        self.prompt.focus_handle(cx)
21597    }
21598}
21599
21600fn all_edits_insertions_or_deletions(
21601    edits: &Vec<(Range<Anchor>, String)>,
21602    snapshot: &MultiBufferSnapshot,
21603) -> bool {
21604    let mut all_insertions = true;
21605    let mut all_deletions = true;
21606
21607    for (range, new_text) in edits.iter() {
21608        let range_is_empty = range.to_offset(&snapshot).is_empty();
21609        let text_is_empty = new_text.is_empty();
21610
21611        if range_is_empty != text_is_empty {
21612            if range_is_empty {
21613                all_deletions = false;
21614            } else {
21615                all_insertions = false;
21616            }
21617        } else {
21618            return false;
21619        }
21620
21621        if !all_insertions && !all_deletions {
21622            return false;
21623        }
21624    }
21625    all_insertions || all_deletions
21626}
21627
21628struct MissingEditPredictionKeybindingTooltip;
21629
21630impl Render for MissingEditPredictionKeybindingTooltip {
21631    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21632        ui::tooltip_container(window, cx, |container, _, cx| {
21633            container
21634                .flex_shrink_0()
21635                .max_w_80()
21636                .min_h(rems_from_px(124.))
21637                .justify_between()
21638                .child(
21639                    v_flex()
21640                        .flex_1()
21641                        .text_ui_sm(cx)
21642                        .child(Label::new("Conflict with Accept Keybinding"))
21643                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21644                )
21645                .child(
21646                    h_flex()
21647                        .pb_1()
21648                        .gap_1()
21649                        .items_end()
21650                        .w_full()
21651                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21652                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21653                        }))
21654                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21655                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21656                        })),
21657                )
21658        })
21659    }
21660}
21661
21662#[derive(Debug, Clone, Copy, PartialEq)]
21663pub struct LineHighlight {
21664    pub background: Background,
21665    pub border: Option<gpui::Hsla>,
21666    pub include_gutter: bool,
21667    pub type_id: Option<TypeId>,
21668}
21669
21670fn render_diff_hunk_controls(
21671    row: u32,
21672    status: &DiffHunkStatus,
21673    hunk_range: Range<Anchor>,
21674    is_created_file: bool,
21675    line_height: Pixels,
21676    editor: &Entity<Editor>,
21677    _window: &mut Window,
21678    cx: &mut App,
21679) -> AnyElement {
21680    h_flex()
21681        .h(line_height)
21682        .mr_1()
21683        .gap_1()
21684        .px_0p5()
21685        .pb_1()
21686        .border_x_1()
21687        .border_b_1()
21688        .border_color(cx.theme().colors().border_variant)
21689        .rounded_b_lg()
21690        .bg(cx.theme().colors().editor_background)
21691        .gap_1()
21692        .occlude()
21693        .shadow_md()
21694        .child(if status.has_secondary_hunk() {
21695            Button::new(("stage", row as u64), "Stage")
21696                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21697                .tooltip({
21698                    let focus_handle = editor.focus_handle(cx);
21699                    move |window, cx| {
21700                        Tooltip::for_action_in(
21701                            "Stage Hunk",
21702                            &::git::ToggleStaged,
21703                            &focus_handle,
21704                            window,
21705                            cx,
21706                        )
21707                    }
21708                })
21709                .on_click({
21710                    let editor = editor.clone();
21711                    move |_event, _window, cx| {
21712                        editor.update(cx, |editor, cx| {
21713                            editor.stage_or_unstage_diff_hunks(
21714                                true,
21715                                vec![hunk_range.start..hunk_range.start],
21716                                cx,
21717                            );
21718                        });
21719                    }
21720                })
21721        } else {
21722            Button::new(("unstage", row as u64), "Unstage")
21723                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21724                .tooltip({
21725                    let focus_handle = editor.focus_handle(cx);
21726                    move |window, cx| {
21727                        Tooltip::for_action_in(
21728                            "Unstage Hunk",
21729                            &::git::ToggleStaged,
21730                            &focus_handle,
21731                            window,
21732                            cx,
21733                        )
21734                    }
21735                })
21736                .on_click({
21737                    let editor = editor.clone();
21738                    move |_event, _window, cx| {
21739                        editor.update(cx, |editor, cx| {
21740                            editor.stage_or_unstage_diff_hunks(
21741                                false,
21742                                vec![hunk_range.start..hunk_range.start],
21743                                cx,
21744                            );
21745                        });
21746                    }
21747                })
21748        })
21749        .child(
21750            Button::new(("restore", row as u64), "Restore")
21751                .tooltip({
21752                    let focus_handle = editor.focus_handle(cx);
21753                    move |window, cx| {
21754                        Tooltip::for_action_in(
21755                            "Restore Hunk",
21756                            &::git::Restore,
21757                            &focus_handle,
21758                            window,
21759                            cx,
21760                        )
21761                    }
21762                })
21763                .on_click({
21764                    let editor = editor.clone();
21765                    move |_event, window, cx| {
21766                        editor.update(cx, |editor, cx| {
21767                            let snapshot = editor.snapshot(window, cx);
21768                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21769                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21770                        });
21771                    }
21772                })
21773                .disabled(is_created_file),
21774        )
21775        .when(
21776            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21777            |el| {
21778                el.child(
21779                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21780                        .shape(IconButtonShape::Square)
21781                        .icon_size(IconSize::Small)
21782                        // .disabled(!has_multiple_hunks)
21783                        .tooltip({
21784                            let focus_handle = editor.focus_handle(cx);
21785                            move |window, cx| {
21786                                Tooltip::for_action_in(
21787                                    "Next Hunk",
21788                                    &GoToHunk,
21789                                    &focus_handle,
21790                                    window,
21791                                    cx,
21792                                )
21793                            }
21794                        })
21795                        .on_click({
21796                            let editor = editor.clone();
21797                            move |_event, window, cx| {
21798                                editor.update(cx, |editor, cx| {
21799                                    let snapshot = editor.snapshot(window, cx);
21800                                    let position =
21801                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
21802                                    editor.go_to_hunk_before_or_after_position(
21803                                        &snapshot,
21804                                        position,
21805                                        Direction::Next,
21806                                        window,
21807                                        cx,
21808                                    );
21809                                    editor.expand_selected_diff_hunks(cx);
21810                                });
21811                            }
21812                        }),
21813                )
21814                .child(
21815                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
21816                        .shape(IconButtonShape::Square)
21817                        .icon_size(IconSize::Small)
21818                        // .disabled(!has_multiple_hunks)
21819                        .tooltip({
21820                            let focus_handle = editor.focus_handle(cx);
21821                            move |window, cx| {
21822                                Tooltip::for_action_in(
21823                                    "Previous Hunk",
21824                                    &GoToPreviousHunk,
21825                                    &focus_handle,
21826                                    window,
21827                                    cx,
21828                                )
21829                            }
21830                        })
21831                        .on_click({
21832                            let editor = editor.clone();
21833                            move |_event, window, cx| {
21834                                editor.update(cx, |editor, cx| {
21835                                    let snapshot = editor.snapshot(window, cx);
21836                                    let point =
21837                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
21838                                    editor.go_to_hunk_before_or_after_position(
21839                                        &snapshot,
21840                                        point,
21841                                        Direction::Prev,
21842                                        window,
21843                                        cx,
21844                                    );
21845                                    editor.expand_selected_diff_hunks(cx);
21846                                });
21847                            }
21848                        }),
21849                )
21850            },
21851        )
21852        .into_any_element()
21853}